feat: commit
This commit is contained in:
parent
fa41ee8a4b
commit
24ead9aad7
22
config/configuration.ts
Normal file
22
config/configuration.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import * as fs from 'fs-extra';
|
||||||
|
import * as yaml from 'js-yaml';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
const ENV_NAME = {
|
||||||
|
development: 'dev',
|
||||||
|
production: 'prod',
|
||||||
|
};
|
||||||
|
|
||||||
|
const env = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
|
export function getConfig() {
|
||||||
|
const filePath = path.join(__dirname, './', `${ENV_NAME[env]}.yaml`);
|
||||||
|
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
throw new Error(`Can not find config file: ${filePath}`);
|
||||||
|
}
|
||||||
|
return yaml.load(fs.readFileSync(filePath, 'utf-8')) as Record<
|
||||||
|
string,
|
||||||
|
unknown
|
||||||
|
>;
|
||||||
|
}
|
25
config/dev.yaml
Normal file
25
config/dev.yaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
server:
|
||||||
|
port: 4399
|
||||||
|
prefix: ""
|
||||||
|
|
||||||
|
# 数据库配置
|
||||||
|
db:
|
||||||
|
mysql:
|
||||||
|
host: "localhost"
|
||||||
|
port: 3306
|
||||||
|
username: "root"
|
||||||
|
password: "123456"
|
||||||
|
database: "travel_app"
|
||||||
|
synchronize: true
|
||||||
|
|
||||||
|
# Jwt配置
|
||||||
|
jwt:
|
||||||
|
secret: "travel_app"
|
||||||
|
expiresIn: "2h"
|
||||||
|
|
||||||
|
# Oss配置
|
||||||
|
oss:
|
||||||
|
accessKeyId: "LTAI5tHfUhFjJ335EVo1vcWm"
|
||||||
|
accessKeySecret: "0q5JF4862ai5pznfIZMTIjThVjzaqK"
|
||||||
|
bucket: "polaris-frontend"
|
||||||
|
dir: "yitu_image/"
|
@ -1,9 +0,0 @@
|
|||||||
// 本地运行是没有 process.env.NODE_ENV 的,借此来区分[开发环境]和[生产环境]
|
|
||||||
const ossConfig = {
|
|
||||||
accessKeyId: 'LTAI5tHfUhFjJ335EVo1vcWm',
|
|
||||||
accessKeySecret: '0q5JF4862ai5pznfIZMTIjThVjzaqK',
|
|
||||||
bucket: 'polaris-frontend',
|
|
||||||
dir: 'yitu_image/',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ossConfig;
|
|
25
config/prod.yaml
Normal file
25
config/prod.yaml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
server:
|
||||||
|
port: 4399
|
||||||
|
prefix: ""
|
||||||
|
|
||||||
|
# 数据库配置
|
||||||
|
db:
|
||||||
|
mysql:
|
||||||
|
host: "rm-uf686x3ni1tiz68z088270.mysql.rds.aliyuncs.com"
|
||||||
|
port: 3306
|
||||||
|
username: "travel_app"
|
||||||
|
password: "travel_app123"
|
||||||
|
database: "travel_app"
|
||||||
|
synchronize: true
|
||||||
|
|
||||||
|
# Jwt配置
|
||||||
|
jwt:
|
||||||
|
secret: "travel_app"
|
||||||
|
expiresIn: "2h"
|
||||||
|
|
||||||
|
# Oss配置
|
||||||
|
oss:
|
||||||
|
accessKeyId: "LTAI5tHfUhFjJ335EVo1vcWm"
|
||||||
|
accessKeySecret: "0q5JF4862ai5pznfIZMTIjThVjzaqK"
|
||||||
|
bucket: "polaris-frontend"
|
||||||
|
dir: "yitu_image/"
|
@ -3,6 +3,7 @@
|
|||||||
"collection": "@nestjs/schematics",
|
"collection": "@nestjs/schematics",
|
||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"deleteOutDir": true
|
"deleteOutDir": true,
|
||||||
|
"assets": [{"include": "../config/*.yaml", "outDir": "./dist/config"}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
package.json
13
package.json
@ -6,7 +6,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "nest build",
|
"build": "NODE_ENV=production nest build",
|
||||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||||
"start": "nest start",
|
"start": "nest start",
|
||||||
"start:dev": "nest start --watch",
|
"start:dev": "nest start --watch",
|
||||||
@ -21,16 +21,25 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^10.0.0",
|
||||||
|
"@nestjs/config": "^3.2.2",
|
||||||
"@nestjs/core": "^10.0.0",
|
"@nestjs/core": "^10.0.0",
|
||||||
|
"@nestjs/jwt": "^10.2.0",
|
||||||
"@nestjs/mapped-types": "*",
|
"@nestjs/mapped-types": "*",
|
||||||
|
"@nestjs/passport": "^10.0.3",
|
||||||
"@nestjs/platform-express": "^10.0.0",
|
"@nestjs/platform-express": "^10.0.0",
|
||||||
"@nestjs/typeorm": "^10.0.2",
|
"@nestjs/typeorm": "^10.0.2",
|
||||||
"@types/ali-oss": "^6.16.11",
|
"@types/ali-oss": "^6.16.11",
|
||||||
"ali-oss": "^6.20.0",
|
"ali-oss": "^6.20.0",
|
||||||
|
"bcryptjs": "^2.4.3",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
|
"class-validator": "^0.14.1",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
|
"fs": "0.0.1-security",
|
||||||
|
"fs-extra": "^11.2.0",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
"multer": "1.4.5-lts.1",
|
"multer": "1.4.5-lts.1",
|
||||||
"mysql2": "^3.9.7",
|
"mysql2": "^3.9.7",
|
||||||
|
"passport-jwt": "^4.0.1",
|
||||||
"reflect-metadata": "^0.2.0",
|
"reflect-metadata": "^0.2.0",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"typeorm": "^0.3.20"
|
"typeorm": "^0.3.20"
|
||||||
@ -41,7 +50,9 @@
|
|||||||
"@nestjs/testing": "^10.0.0",
|
"@nestjs/testing": "^10.0.0",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/jest": "^29.5.2",
|
"@types/jest": "^29.5.2",
|
||||||
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@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",
|
||||||
|
8095
pnpm-lock.yaml
generated
8095
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -3,32 +3,48 @@ import { AppController } from './app.controller';
|
|||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { UserEntity } from './user/entities/user.entity';
|
import { UserEntity } from './user/entities/user.entity';
|
||||||
import { BannerEntity } from './banner/entities/banner.entity';
|
import { BannerEntity } from './banner/entities/banner.entity';
|
||||||
|
import { AuthEntity } from './auth/entities/auth.entity';
|
||||||
import { UserModule } from './user/user.module';
|
import { UserModule } from './user/user.module';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||||
import { BannerModule } from './banner/banner.module';
|
import { BannerModule } from './banner/banner.module';
|
||||||
import { OssModule } from './oss/oss.module';
|
import { OssModule } from './oss/oss.module';
|
||||||
import { SysUserModule } from './sys-user/sys-user.module';
|
import { AuthModule } from './auth/auth.module';
|
||||||
|
import { APP_GUARD } from '@nestjs/core';
|
||||||
|
import { jwtAuthGuard } from './jwt/jwt-auth.grard';
|
||||||
|
import { getConfig } from 'config/configuration';
|
||||||
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
const ENTITIES = [UserEntity, BannerEntity];
|
const ENTITIES = [UserEntity, BannerEntity, AuthEntity];
|
||||||
|
|
||||||
const MODULE = [UserModule, BannerModule, OssModule];
|
const MODULE = [UserModule, BannerModule, OssModule, AuthModule];
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forRoot({
|
ConfigModule.forRoot({
|
||||||
|
cache: true,
|
||||||
|
load: [getConfig],
|
||||||
|
isGlobal: true,
|
||||||
|
}),
|
||||||
|
TypeOrmModule.forRootAsync({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
inject: [ConfigService],
|
||||||
|
useFactory: (config: ConfigService) => {
|
||||||
|
return {
|
||||||
type: 'mysql',
|
type: 'mysql',
|
||||||
host: 'localhost',
|
entities: ENTITIES,
|
||||||
port: 3306,
|
...config.get('db.mysql'),
|
||||||
username: 'root',
|
} as TypeOrmModuleOptions;
|
||||||
password: '123456',
|
},
|
||||||
database: 'travel-app',
|
|
||||||
entities: ENTITIES, // 这里添加实体类
|
|
||||||
synchronize: true,
|
|
||||||
}),
|
}),
|
||||||
...MODULE,
|
...MODULE,
|
||||||
SysUserModule,
|
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [
|
||||||
|
AppService,
|
||||||
|
{
|
||||||
|
provide: APP_GUARD,
|
||||||
|
useClass: jwtAuthGuard,
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
20
src/auth/auth.controller.spec.ts
Normal file
20
src/auth/auth.controller.spec.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { AuthController } from './auth.controller';
|
||||||
|
import { AuthService } from './auth.service';
|
||||||
|
|
||||||
|
describe('AuthController', () => {
|
||||||
|
let controller: AuthController;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [AuthController],
|
||||||
|
providers: [AuthService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
controller = module.get<AuthController>(AuthController);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
37
src/auth/auth.controller.ts
Normal file
37
src/auth/auth.controller.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Request,
|
||||||
|
UseGuards,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { AuthService } from './auth.service';
|
||||||
|
import { CreateAuthDto } from './dto/create-auth.dto';
|
||||||
|
import { Public } from 'src/common/public.decorator';
|
||||||
|
import { jwtAuthGuard } from 'src/jwt/jwt-auth.grard';
|
||||||
|
|
||||||
|
@Controller('auth')
|
||||||
|
export class AuthController {
|
||||||
|
constructor(private readonly authService: AuthService) {}
|
||||||
|
// 注册
|
||||||
|
@Public()
|
||||||
|
@Post('/signup')
|
||||||
|
signup(@Body() signupData: CreateAuthDto) {
|
||||||
|
console.log('>>>>>signupData', signupData);
|
||||||
|
return this.authService.signup(signupData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录
|
||||||
|
@Public()
|
||||||
|
@Post('/login')
|
||||||
|
login(@Body() loginData: CreateAuthDto) {
|
||||||
|
return this.authService.login(loginData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(jwtAuthGuard)
|
||||||
|
@Get('/user')
|
||||||
|
getuserInfo(@Request() req) {
|
||||||
|
return this.authService.getUserInfo(req.user.id);
|
||||||
|
}
|
||||||
|
}
|
25
src/auth/auth.module.ts
Normal file
25
src/auth/auth.module.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { AuthService } from './auth.service';
|
||||||
|
import { AuthController } from './auth.controller';
|
||||||
|
import { AuthEntity } from './entities/auth.entity';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
|
import JwtAuthStrategy from 'src/jwt/jwt-auth.strategy';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
TypeOrmModule.forFeature([AuthEntity]),
|
||||||
|
JwtModule.registerAsync({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
useFactory: async (configService: ConfigService) => ({
|
||||||
|
secret: configService.get('jwt.secret'),
|
||||||
|
signOptions: { expiresIn: configService.get('jwt.expiresIn') },
|
||||||
|
}),
|
||||||
|
inject: [ConfigService],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
controllers: [AuthController],
|
||||||
|
providers: [AuthService, JwtAuthStrategy],
|
||||||
|
})
|
||||||
|
export class AuthModule {}
|
@ -1,15 +1,15 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { SysUserService } from './sys-user.service';
|
import { AuthService } from './auth.service';
|
||||||
|
|
||||||
describe('SysUserService', () => {
|
describe('AuthService', () => {
|
||||||
let service: SysUserService;
|
let service: AuthService;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [SysUserService],
|
providers: [AuthService],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
service = module.get<SysUserService>(SysUserService);
|
service = module.get<AuthService>(AuthService);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be defined', () => {
|
it('should be defined', () => {
|
55
src/auth/auth.service.ts
Normal file
55
src/auth/auth.service.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { CreateAuthDto } from './dto/create-auth.dto';
|
||||||
|
import { AuthEntity } from './entities/auth.entity';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { JwtService } from '@nestjs/jwt';
|
||||||
|
import * as bcryptjs from 'bcryptjs';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AuthService {
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(AuthEntity) private readonly user: Repository<AuthEntity>,
|
||||||
|
private readonly jwtService: JwtService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async signup(signupData: CreateAuthDto) {
|
||||||
|
const findUser = await this.user.findOne({
|
||||||
|
where: { username: signupData.username },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (findUser && findUser.username === signupData.username)
|
||||||
|
return '用户已注册';
|
||||||
|
signupData.password = bcryptjs.hashSync(signupData.password, 10);
|
||||||
|
this.user.save(signupData);
|
||||||
|
return '注册成功';
|
||||||
|
}
|
||||||
|
|
||||||
|
async login(loginData: CreateAuthDto) {
|
||||||
|
const findUser = await this.user.findOne({
|
||||||
|
where: { username: loginData.username },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!findUser) return '用户不存在';
|
||||||
|
|
||||||
|
const compareRes: boolean = bcryptjs.compareSync(
|
||||||
|
loginData.password,
|
||||||
|
findUser.password,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!compareRes) return { msg: '账号或者密码不正确' };
|
||||||
|
const payload = { id: findUser.id, username: findUser.username };
|
||||||
|
|
||||||
|
return {
|
||||||
|
token: this.jwtService.sign(payload),
|
||||||
|
msg: '登录成功',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUserInfo(userId: number) {
|
||||||
|
const { password, ...result } = await this.user.findOne({
|
||||||
|
where: { id: userId },
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
14
src/auth/dto/create-auth.dto.ts
Normal file
14
src/auth/dto/create-auth.dto.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { IsString, IsNotEmpty, MinLength } from 'class-validator';
|
||||||
|
|
||||||
|
export class CreateAuthDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@MinLength(6, {
|
||||||
|
message: '密码不能少于六位',
|
||||||
|
})
|
||||||
|
password: string;
|
||||||
|
}
|
4
src/auth/dto/update-auth.dto.ts
Normal file
4
src/auth/dto/update-auth.dto.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { PartialType } from '@nestjs/mapped-types';
|
||||||
|
import { CreateAuthDto } from './create-auth.dto';
|
||||||
|
|
||||||
|
export class UpdateAuthDto extends PartialType(CreateAuthDto) {}
|
19
src/auth/entities/auth.entity.ts
Normal file
19
src/auth/entities/auth.entity.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class AuthEntity {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
password: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default:
|
||||||
|
'https://polaris-frontend.oss-cn-shanghai.aliyuncs.com/yitu_image/1717148513267default_user.png',
|
||||||
|
})
|
||||||
|
avatar: string;
|
||||||
|
}
|
4
src/common/public.decorator.ts
Normal file
4
src/common/public.decorator.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { SetMetadata } from '@nestjs/common';
|
||||||
|
|
||||||
|
export const IS_PUBLIC_KEY = 'isPublic';
|
||||||
|
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
|
@ -3,6 +3,7 @@ import {
|
|||||||
Catch,
|
Catch,
|
||||||
ArgumentsHost,
|
ArgumentsHost,
|
||||||
HttpException,
|
HttpException,
|
||||||
|
HttpStatus,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Response } from 'express';
|
import { Response } from 'express';
|
||||||
|
|
||||||
@ -11,11 +12,18 @@ export class HttpExceptionFilter implements ExceptionFilter {
|
|||||||
catch(exception: HttpException, host: ArgumentsHost) {
|
catch(exception: HttpException, host: ArgumentsHost) {
|
||||||
const ctx = host.switchToHttp();
|
const ctx = host.switchToHttp();
|
||||||
const response = ctx.getResponse<Response>();
|
const response = ctx.getResponse<Response>();
|
||||||
const status = exception.getStatus();
|
const status = exception.getStatus
|
||||||
|
? exception.getStatus()
|
||||||
|
: HttpStatus.INTERNAL_SERVER_ERROR;
|
||||||
|
const exceptionResponse = exception.getResponse() as { message };
|
||||||
|
const errorMessage = exceptionResponse.message
|
||||||
|
? exceptionResponse.message
|
||||||
|
: exception.message;
|
||||||
response.status(status).json({
|
response.status(status).json({
|
||||||
code: 1,
|
code: status,
|
||||||
message: '服务错误',
|
message: Array.isArray(errorMessage)
|
||||||
|
? errorMessage.join(',')
|
||||||
|
: errorMessage,
|
||||||
data: null,
|
data: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
23
src/jwt/jwt-auth.grard.ts
Normal file
23
src/jwt/jwt-auth.grard.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ExecutionContext, Injectable } from '@nestjs/common';
|
||||||
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { IS_PUBLIC_KEY } from 'src/common/public.decorator';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class jwtAuthGuard extends AuthGuard('jwt') {
|
||||||
|
constructor(private reflector: Reflector) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
canActivate(
|
||||||
|
context: ExecutionContext,
|
||||||
|
): boolean | Promise<boolean> | Observable<boolean> {
|
||||||
|
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
|
||||||
|
context.getHandler(),
|
||||||
|
context.getClass(),
|
||||||
|
]);
|
||||||
|
if (isPublic) return true;
|
||||||
|
return super.canActivate(context);
|
||||||
|
}
|
||||||
|
}
|
29
src/jwt/jwt-auth.strategy.ts
Normal file
29
src/jwt/jwt-auth.strategy.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { PassportStrategy } from '@nestjs/passport';
|
||||||
|
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
|
export interface JwtPayload {
|
||||||
|
id: number;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
// 验证请求头中的token
|
||||||
|
export default class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') {
|
||||||
|
constructor(private readonly configService: ConfigService) {
|
||||||
|
super({
|
||||||
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||||
|
ignoreExpiration: false,
|
||||||
|
secretOrKey: configService.get('jwt.secret'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async validate(payload: JwtPayload) {
|
||||||
|
const { username, id } = payload;
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
username,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
10
src/main.ts
10
src/main.ts
@ -1,3 +1,4 @@
|
|||||||
|
import { ValidationPipe } from '@nestjs/common';
|
||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
import { HttpExceptionFilter } from './http-exception/http-exception.filter';
|
import { HttpExceptionFilter } from './http-exception/http-exception.filter';
|
||||||
@ -6,11 +7,16 @@ import { TransformInterceptor } from './transoform/transform.interceptor';
|
|||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
// 设置全局路由前缀,例如 'api'
|
// 设置全局路由前缀,例如 'api'
|
||||||
app.setGlobalPrefix('api');
|
|
||||||
app.enableCors();
|
app.enableCors();
|
||||||
|
app.useGlobalPipes(
|
||||||
|
new ValidationPipe({
|
||||||
|
transform: true,
|
||||||
|
whitelist: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
app.useGlobalFilters(new HttpExceptionFilter());
|
app.useGlobalFilters(new HttpExceptionFilter());
|
||||||
app.useGlobalInterceptors(new TransformInterceptor());
|
app.useGlobalInterceptors(new TransformInterceptor());
|
||||||
// 如果有全局拦截器,确保添加它
|
// 如果有全局拦截器,确保添加它
|
||||||
await app.listen(3000);
|
await app.listen(4399);
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { OssService } from './oss.service';
|
import { OssService } from './oss.service';
|
||||||
import { OssController } from './oss.controller';
|
import { OssController } from './oss.controller';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [ConfigModule],
|
||||||
controllers: [OssController],
|
controllers: [OssController],
|
||||||
providers: [OssService],
|
providers: [OssService],
|
||||||
})
|
})
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import * as OSS from 'ali-oss';
|
import * as OSS from 'ali-oss';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import ossConfig from '../../config/oss';
|
|
||||||
import * as dayjs from 'dayjs';
|
import * as dayjs from 'dayjs';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class OssService {
|
export class OssService {
|
||||||
|
constructor(private configService: ConfigService) {}
|
||||||
async getSignature() {
|
async getSignature() {
|
||||||
|
const ossConfig = this.configService.get('oss');
|
||||||
const config = {
|
const config = {
|
||||||
// 填写你自己的 AccessKey
|
// 填写你自己的 AccessKey
|
||||||
accessKeyId: ossConfig.accessKeyId,
|
accessKeyId: ossConfig.accessKeyId,
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export class CreateSysUserDto {}
|
|
@ -1,4 +0,0 @@
|
|||||||
import { PartialType } from '@nestjs/mapped-types';
|
|
||||||
import { CreateSysUserDto } from './create-sys-user.dto';
|
|
||||||
|
|
||||||
export class UpdateSysUserDto extends PartialType(CreateSysUserDto) {}
|
|
@ -1,13 +0,0 @@
|
|||||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
|
||||||
|
|
||||||
@Entity()
|
|
||||||
export class SysUserEntity {
|
|
||||||
@PrimaryGeneratedColumn()
|
|
||||||
id: number;
|
|
||||||
|
|
||||||
@Column()
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Column()
|
|
||||||
password: string;
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { SysUserController } from './sys-user.controller';
|
|
||||||
import { SysUserService } from './sys-user.service';
|
|
||||||
|
|
||||||
describe('SysUserController', () => {
|
|
||||||
let controller: SysUserController;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
controllers: [SysUserController],
|
|
||||||
providers: [SysUserService],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
controller = module.get<SysUserController>(SysUserController);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be defined', () => {
|
|
||||||
expect(controller).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,42 +0,0 @@
|
|||||||
import {
|
|
||||||
Controller,
|
|
||||||
Get,
|
|
||||||
Post,
|
|
||||||
Body,
|
|
||||||
Patch,
|
|
||||||
Param,
|
|
||||||
Delete,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { SysUserService } from './sys-user.service';
|
|
||||||
import { CreateSysUserDto } from './dto/create-sys-user.dto';
|
|
||||||
import { UpdateSysUserDto } from './dto/update-sys-user.dto';
|
|
||||||
|
|
||||||
@Controller('sys-user')
|
|
||||||
export class SysUserController {
|
|
||||||
constructor(private readonly sysUserService: SysUserService) {}
|
|
||||||
|
|
||||||
@Post()
|
|
||||||
create(@Body() createSysUserDto: CreateSysUserDto) {
|
|
||||||
return this.sysUserService.create(createSysUserDto);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get()
|
|
||||||
findAll() {
|
|
||||||
return this.sysUserService.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get(':id')
|
|
||||||
findOne(@Param('id') id: string) {
|
|
||||||
return this.sysUserService.findOne(+id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Patch(':id')
|
|
||||||
update(@Param('id') id: string, @Body() updateSysUserDto: UpdateSysUserDto) {
|
|
||||||
return this.sysUserService.update(+id, updateSysUserDto);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Delete(':id')
|
|
||||||
remove(@Param('id') id: string) {
|
|
||||||
return this.sysUserService.remove(+id);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
import { Module } from '@nestjs/common';
|
|
||||||
import { SysUserService } from './sys-user.service';
|
|
||||||
import { SysUserController } from './sys-user.controller';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
controllers: [SysUserController],
|
|
||||||
providers: [SysUserService],
|
|
||||||
})
|
|
||||||
export class SysUserModule {}
|
|
@ -1,26 +0,0 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { CreateSysUserDto } from './dto/create-sys-user.dto';
|
|
||||||
import { UpdateSysUserDto } from './dto/update-sys-user.dto';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class SysUserService {
|
|
||||||
create(createSysUserDto: CreateSysUserDto) {
|
|
||||||
return 'This action adds a new sysUser';
|
|
||||||
}
|
|
||||||
|
|
||||||
findAll() {
|
|
||||||
return `This action returns all sysUser`;
|
|
||||||
}
|
|
||||||
|
|
||||||
findOne(id: number) {
|
|
||||||
return `This action returns a #${id} sysUser`;
|
|
||||||
}
|
|
||||||
|
|
||||||
update(id: number, updateSysUserDto: UpdateSysUserDto) {
|
|
||||||
return `This action updates a #${id} sysUser`;
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(id: number) {
|
|
||||||
return `This action removes a #${id} sysUser`;
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,7 @@ import {
|
|||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { classToPlain } from 'class-transformer';
|
import { instanceToPlain } from 'class-transformer';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TransformInterceptor implements NestInterceptor {
|
export class TransformInterceptor implements NestInterceptor {
|
||||||
@ -15,8 +15,8 @@ export class TransformInterceptor implements NestInterceptor {
|
|||||||
map((data) => {
|
map((data) => {
|
||||||
return {
|
return {
|
||||||
code: 0,
|
code: 0,
|
||||||
data: classToPlain(data),
|
data: instanceToPlain(data),
|
||||||
message: null,
|
message: 'ok',
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user