feat: 添加token相关代码
This commit is contained in:
parent
d2f6d3ebcc
commit
946be43558
1
.env
1
.env
|
|
@ -1,5 +1,6 @@
|
||||||
JWT_SECRET=5270e53a05600cb1f19b287a915b1c792d7552cbaae261afb6dcaf988d0db10f
|
JWT_SECRET=5270e53a05600cb1f19b287a915b1c792d7552cbaae261afb6dcaf988d0db10f
|
||||||
SERVER_HOST='192.144.32.178'
|
SERVER_HOST='192.144.32.178'
|
||||||
SERVER_PORT=3306
|
SERVER_PORT=3306
|
||||||
|
SERVER_USER='root'
|
||||||
PASSWORD='lichao1314'
|
PASSWORD='lichao1314'
|
||||||
DB_NAME='auth_db'
|
DB_NAME='auth_db'
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
"install": "^0.13.0",
|
"install": "^0.13.0",
|
||||||
"mysql2": "^3.12.0",
|
"mysql2": "^3.12.0",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
|
"passport-jwt": "^4.0.1",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
|
|
@ -48,6 +49,7 @@
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/jest": "^29.5.2",
|
"@types/jest": "^29.5.2",
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.3.1",
|
||||||
|
"@types/passport-jwt": "^4.0.1",
|
||||||
"@types/supertest": "^6.0.0",
|
"@types/supertest": "^6.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||||
"@typescript-eslint/parser": "^6.0.0",
|
"@typescript-eslint/parser": "^6.0.0",
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ specifiers:
|
||||||
'@types/express': ^4.17.17
|
'@types/express': ^4.17.17
|
||||||
'@types/jest': ^29.5.2
|
'@types/jest': ^29.5.2
|
||||||
'@types/node': ^20.3.1
|
'@types/node': ^20.3.1
|
||||||
|
'@types/passport-jwt': ^4.0.1
|
||||||
'@types/supertest': ^6.0.0
|
'@types/supertest': ^6.0.0
|
||||||
'@types/uuid': ^10.0.0
|
'@types/uuid': ^10.0.0
|
||||||
'@typescript-eslint/eslint-plugin': ^6.0.0
|
'@typescript-eslint/eslint-plugin': ^6.0.0
|
||||||
|
|
@ -29,6 +30,7 @@ specifiers:
|
||||||
jest: ^29.5.0
|
jest: ^29.5.0
|
||||||
mysql2: ^3.12.0
|
mysql2: ^3.12.0
|
||||||
passport: ^0.7.0
|
passport: ^0.7.0
|
||||||
|
passport-jwt: ^4.0.1
|
||||||
passport-local: ^1.0.0
|
passport-local: ^1.0.0
|
||||||
prettier: ^3.0.0
|
prettier: ^3.0.0
|
||||||
reflect-metadata: ^0.1.13
|
reflect-metadata: ^0.1.13
|
||||||
|
|
@ -59,6 +61,7 @@ dependencies:
|
||||||
install: 0.13.0
|
install: 0.13.0
|
||||||
mysql2: 3.12.0
|
mysql2: 3.12.0
|
||||||
passport: 0.7.0
|
passport: 0.7.0
|
||||||
|
passport-jwt: 4.0.1
|
||||||
passport-local: 1.0.0
|
passport-local: 1.0.0
|
||||||
reflect-metadata: 0.1.14
|
reflect-metadata: 0.1.14
|
||||||
rxjs: 7.8.1
|
rxjs: 7.8.1
|
||||||
|
|
@ -72,6 +75,7 @@ devDependencies:
|
||||||
'@types/express': 4.17.21
|
'@types/express': 4.17.21
|
||||||
'@types/jest': 29.5.14
|
'@types/jest': 29.5.14
|
||||||
'@types/node': 20.17.12
|
'@types/node': 20.17.12
|
||||||
|
'@types/passport-jwt': 4.0.1
|
||||||
'@types/supertest': 6.0.2
|
'@types/supertest': 6.0.2
|
||||||
'@typescript-eslint/eslint-plugin': 6.21.0_wj7xg5aijo4gzz5szz6d7vhele
|
'@typescript-eslint/eslint-plugin': 6.21.0_wj7xg5aijo4gzz5szz6d7vhele
|
||||||
'@typescript-eslint/parser': 6.21.0_6txzh3afdjfsavlpa2fczfkiua
|
'@typescript-eslint/parser': 6.21.0_6txzh3afdjfsavlpa2fczfkiua
|
||||||
|
|
@ -1295,7 +1299,6 @@ packages:
|
||||||
resolution: {integrity: sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==}
|
resolution: {integrity: sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.17.12
|
'@types/node': 20.17.12
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@types/methods/1.1.4:
|
/@types/methods/1.1.4:
|
||||||
resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==}
|
resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==}
|
||||||
|
|
@ -1310,6 +1313,26 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.19.8
|
undici-types: 6.19.8
|
||||||
|
|
||||||
|
/@types/passport-jwt/4.0.1:
|
||||||
|
resolution: {integrity: sha512-Y0Ykz6nWP4jpxgEUYq8NoVZeCQPo1ZndJLfapI249g1jHChvRfZRO/LS3tqu26YgAS/laI1qx98sYGz0IalRXQ==}
|
||||||
|
dependencies:
|
||||||
|
'@types/jsonwebtoken': 9.0.5
|
||||||
|
'@types/passport-strategy': 0.2.38
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/passport-strategy/0.2.38:
|
||||||
|
resolution: {integrity: sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/express': 4.17.21
|
||||||
|
'@types/passport': 1.0.17
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/passport/1.0.17:
|
||||||
|
resolution: {integrity: sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==}
|
||||||
|
dependencies:
|
||||||
|
'@types/express': 4.17.21
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/qs/6.9.17:
|
/@types/qs/6.9.17:
|
||||||
resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==}
|
resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
@ -4544,6 +4567,13 @@ packages:
|
||||||
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
/passport-jwt/4.0.1:
|
||||||
|
resolution: {integrity: sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==}
|
||||||
|
dependencies:
|
||||||
|
jsonwebtoken: 9.0.2
|
||||||
|
passport-strategy: 1.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/passport-local/1.0.0:
|
/passport-local/1.0.0:
|
||||||
resolution: {integrity: sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==}
|
resolution: {integrity: sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==}
|
||||||
engines: {node: '>= 0.4.0'}
|
engines: {node: '>= 0.4.0'}
|
||||||
|
|
|
||||||
17
src/main.ts
17
src/main.ts
|
|
@ -1,21 +1,28 @@
|
||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
import * as mysql from 'mysql2/promise';
|
import * as mysql from 'mysql2/promise';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
|
// 启动 Nest 应用
|
||||||
|
const app = await NestFactory.create(AppModule);
|
||||||
|
const configService = app.get(ConfigService); // 获取 ConfigService 实例
|
||||||
// 连接 MySQL
|
// 连接 MySQL
|
||||||
const connection = await mysql.createConnection({
|
const connection = await mysql.createConnection({
|
||||||
host: '192.144.32.178',
|
host: configService.get('SERVER_HOST'),
|
||||||
user: 'root',
|
user: configService.get('SERVER_USER'),
|
||||||
password: 'lichao1314',
|
password: configService.get('PASSWORD'),
|
||||||
});
|
});
|
||||||
|
|
||||||
// 创建数据库(如果不存在)
|
// 创建数据库(如果不存在)
|
||||||
await connection.query('CREATE DATABASE IF NOT EXISTS auth_db');
|
await connection.query('CREATE DATABASE IF NOT EXISTS auth_db');
|
||||||
await connection.end();
|
await connection.end();
|
||||||
|
|
||||||
// 启动 Nest 应用
|
app.enableCors({
|
||||||
const app = await NestFactory.create(AppModule);
|
origin: 'http://localhost:8000', // 只允许该来源访问
|
||||||
|
credentials: true, // 允许带有凭证(cookies)的请求
|
||||||
|
});
|
||||||
|
|
||||||
await app.listen(3030);
|
await app.listen(3030);
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Controller, Post, Body } from '@nestjs/common';
|
import { Controller, Post, Body, UnauthorizedException } from '@nestjs/common';
|
||||||
import { UserService } from '../user/user.service';
|
import { UserService } from '../user/user.service';
|
||||||
|
|
||||||
@Controller('user')
|
@Controller('user')
|
||||||
|
|
@ -11,7 +11,12 @@ export class UserController {
|
||||||
) {
|
) {
|
||||||
const { username, password, email } = body;
|
const { username, password, email } = body;
|
||||||
const user = await this.userService.createUser(username, password, email);
|
const user = await this.userService.createUser(username, password, email);
|
||||||
return { message: 'User registered successfully', user };
|
const token = await this.userService.generateToken(user);
|
||||||
|
return {
|
||||||
|
message: 'User registered successfully',
|
||||||
|
user,
|
||||||
|
...token,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('login')
|
@Post('login')
|
||||||
|
|
@ -19,15 +24,20 @@ export class UserController {
|
||||||
const { username, password } = body;
|
const { username, password } = body;
|
||||||
const user = await this.userService.findUserByUsername(username);
|
const user = await this.userService.findUserByUsername(username);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error('User not found');
|
throw new UnauthorizedException('User not found');
|
||||||
}
|
}
|
||||||
const isValidPassword = await this.userService.validatePassword(
|
const isValidPassword = await this.userService.validatePassword(
|
||||||
password,
|
password,
|
||||||
user.password,
|
user.password,
|
||||||
);
|
);
|
||||||
if (!isValidPassword) {
|
if (!isValidPassword) {
|
||||||
throw new Error('Invalid password');
|
throw new UnauthorizedException('Invalid password');
|
||||||
}
|
}
|
||||||
return { message: 'Login successful', user };
|
const token = await this.userService.generateToken(user);
|
||||||
|
return {
|
||||||
|
message: 'Login successful',
|
||||||
|
user,
|
||||||
|
...token,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,18 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
import { UserService } from './user.service';
|
import { UserService } from './user.service';
|
||||||
import { User } from './entities/user.entity';
|
import { User } from './entities/user.entity';
|
||||||
import { UserController } from './user.controller';
|
import { UserController } from './user.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [TypeOrmModule.forFeature([User])],
|
imports: [
|
||||||
|
TypeOrmModule.forFeature([User]),
|
||||||
|
JwtModule.register({
|
||||||
|
secret: 'your-secret-key', // 建议从环境变量中读取
|
||||||
|
signOptions: { expiresIn: '24h' },
|
||||||
|
}),
|
||||||
|
],
|
||||||
providers: [UserService],
|
providers: [UserService],
|
||||||
exports: [UserService],
|
exports: [UserService],
|
||||||
controllers: [UserController],
|
controllers: [UserController],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
import { JwtService } from '@nestjs/jwt';
|
||||||
import { User } from './entities/user.entity';
|
import { User } from './entities/user.entity';
|
||||||
import * as bcrypt from 'bcrypt';
|
import * as bcrypt from 'bcrypt';
|
||||||
|
|
||||||
|
|
@ -9,6 +10,7 @@ export class UserService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(User)
|
@InjectRepository(User)
|
||||||
private userRepository: Repository<User>,
|
private userRepository: Repository<User>,
|
||||||
|
private jwtService: JwtService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async createUser(username: string, password: string, email: string) {
|
async createUser(username: string, password: string, email: string) {
|
||||||
|
|
@ -39,4 +41,14 @@ export class UserService {
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
return bcrypt.compare(plainPassword, hashedPassword);
|
return bcrypt.compare(plainPassword, hashedPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async generateToken(user: User) {
|
||||||
|
const payload = {
|
||||||
|
sub: user.id,
|
||||||
|
username: user.username,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
access_token: this.jwtService.sign(payload),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue