add user module and jwt
This commit is contained in:
parent
1e043718b4
commit
85b2062a2a
@ -1,9 +1,9 @@
|
|||||||
import { BadGatewayException, Global, Module, ModuleMetadata, Type } from '@nestjs/common';
|
import { BadGatewayException, Global, Module, ModuleMetadata, Type } from '@nestjs/common';
|
||||||
|
|
||||||
import { APP_FILTER, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
|
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
|
||||||
import { useContainer } from 'class-validator';
|
import { useContainer } from 'class-validator';
|
||||||
|
|
||||||
import { omit } from 'lodash';
|
import { isNil, omit } from 'lodash';
|
||||||
|
|
||||||
import { ConfigModule } from '@/modules/config/config.module';
|
import { ConfigModule } from '@/modules/config/config.module';
|
||||||
import { Configure } from '@/modules/config/configure';
|
import { Configure } from '@/modules/config/configure';
|
||||||
@ -85,6 +85,13 @@ export async function createBootModule(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isNil(globals.guard)) {
|
||||||
|
providers.push({
|
||||||
|
provide: APP_GUARD,
|
||||||
|
useClass: globals.guard,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return CreateModule('BootModule', () => ({
|
return CreateModule('BootModule', () => ({
|
||||||
imports,
|
imports,
|
||||||
providers,
|
providers,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { ModuleMetadata, PipeTransform, Type } from '@nestjs/common';
|
import { ModuleMetadata, PipeTransform, Type } from '@nestjs/common';
|
||||||
|
import { IAuthGuard } from '@nestjs/passport';
|
||||||
import { NestFastifyApplication } from '@nestjs/platform-fastify';
|
import { NestFastifyApplication } from '@nestjs/platform-fastify';
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@ -28,6 +29,11 @@ export interface CreateOptions {
|
|||||||
interceptor?: Type<any> | null;
|
interceptor?: Type<any> | null;
|
||||||
|
|
||||||
filter?: Type<any> | null;
|
filter?: Type<any> | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局守卫
|
||||||
|
*/
|
||||||
|
guard?: Type<IAuthGuard>;
|
||||||
};
|
};
|
||||||
|
|
||||||
providers?: ModuleMetadata['providers'];
|
providers?: ModuleMetadata['providers'];
|
||||||
|
@ -38,3 +38,5 @@ export const TokenConst = {
|
|||||||
USER_REFRESH_TOKEN_EXPIRED: 'USER_REFRESH_TOKEN_EXPIRED',
|
USER_REFRESH_TOKEN_EXPIRED: 'USER_REFRESH_TOKEN_EXPIRED',
|
||||||
DEFAULT_USER_REFRESH_TOKEN_EXPIRED: 'my-refresh-secret',
|
DEFAULT_USER_REFRESH_TOKEN_EXPIRED: 'my-refresh-secret',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ALLOW_GUEST = 'allowGuest';
|
||||||
|
5
src/modules/user/decorators/guest.decorator.ts
Normal file
5
src/modules/user/decorators/guest.decorator.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { SetMetadata } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { ALLOW_GUEST } from '@/modules/user/constants';
|
||||||
|
|
||||||
|
export const Guest = () => SetMetadata(ALLOW_GUEST, true);
|
8
src/modules/user/decorators/user.request.decorator.ts
Normal file
8
src/modules/user/decorators/user.request.decorator.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { UserEntity } from '../entities/UserEntity';
|
||||||
|
|
||||||
|
export const RequestUser = createParamDecorator(async (_data: unknown, ctx: ExecutionContext) => {
|
||||||
|
const request = ctx.switchToHttp().getRequest();
|
||||||
|
return request.user as ClassToPlain<UserEntity>;
|
||||||
|
});
|
82
src/modules/user/guards/jwt.auth.guard.ts
Normal file
82
src/modules/user/guards/jwt.auth.guard.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
|
|
||||||
|
import { isNil } from 'lodash';
|
||||||
|
|
||||||
|
import { ExtractJwt } from 'passport-jwt';
|
||||||
|
|
||||||
|
import { TokenService } from '@/modules/user/services/token.service';
|
||||||
|
|
||||||
|
import { ALLOW_GUEST } from '../constants';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class JwtAuthGuard extends AuthGuard('jwt') {
|
||||||
|
constructor(
|
||||||
|
protected ref: Reflector,
|
||||||
|
protected tokenService: TokenService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext) {
|
||||||
|
const allowGuest = this.ref.getAllAndOverride<boolean>(ALLOW_GUEST, [
|
||||||
|
context.getHandler(),
|
||||||
|
context.getClass(),
|
||||||
|
]);
|
||||||
|
if (allowGuest) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const request = this.getRequest(context);
|
||||||
|
|
||||||
|
const requestToken = ExtractJwt.fromAuthHeaderAsBearerToken()(request);
|
||||||
|
if (isNil(requestToken)) {
|
||||||
|
throw new UnauthorizedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
const accessToken = await this.tokenService.checkAccessToken(requestToken);
|
||||||
|
if (isNil(accessToken)) {
|
||||||
|
throw new UnauthorizedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (await super.canActivate(context)) as boolean;
|
||||||
|
} catch {
|
||||||
|
const response = this.getResponse(context);
|
||||||
|
const token = await this.tokenService.refreshToken(accessToken, response);
|
||||||
|
if (isNil(token)) {
|
||||||
|
throw new UnauthorizedException();
|
||||||
|
}
|
||||||
|
if (token.accessToken) {
|
||||||
|
request.headers.authorization = `Bearer ${token.accessToken.value}`;
|
||||||
|
}
|
||||||
|
return (await super.canActivate(context)) as boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动请求处理
|
||||||
|
* 如果请求中有错误则抛出错误
|
||||||
|
* 如果请求中没有用户信息则抛出401异常
|
||||||
|
* @param err
|
||||||
|
* @param user
|
||||||
|
* @param _info
|
||||||
|
*/
|
||||||
|
handleRequest(err: any, user: any, _info: any) {
|
||||||
|
if (err || isNil(user)) {
|
||||||
|
if (isNil(user)) {
|
||||||
|
throw new UnauthorizedException();
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRequest(context: ExecutionContext) {
|
||||||
|
return context.switchToHttp().getRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
getResponse(context: ExecutionContext) {
|
||||||
|
return context.switchToHttp().getResponse();
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ import { MeiliModule } from './modules/meilisearch/meili.module';
|
|||||||
import { Restful } from './modules/restful/restful';
|
import { Restful } from './modules/restful/restful';
|
||||||
import { RestfulModule } from './modules/restful/restful.module';
|
import { RestfulModule } from './modules/restful/restful.module';
|
||||||
import { ApiConfig } from './modules/restful/types';
|
import { ApiConfig } from './modules/restful/types';
|
||||||
|
import { JwtAuthGuard } from './modules/user/guards/jwt.auth.guard';
|
||||||
|
|
||||||
export const createOptions: CreateOptions = {
|
export const createOptions: CreateOptions = {
|
||||||
commands: () => [...Object.values(dbCommands)],
|
commands: () => [...Object.values(dbCommands)],
|
||||||
@ -26,7 +27,7 @@ export const createOptions: CreateOptions = {
|
|||||||
await RestfulModule.forRoot(configure),
|
await RestfulModule.forRoot(configure),
|
||||||
await ContentModule.forRoot(configure),
|
await ContentModule.forRoot(configure),
|
||||||
],
|
],
|
||||||
globals: {},
|
globals: { guard: JwtAuthGuard },
|
||||||
builder: async ({ configure, BootModule }) => {
|
builder: async ({ configure, BootModule }) => {
|
||||||
const container = await NestFactory.create<NestFastifyApplication>(
|
const container = await NestFactory.create<NestFastifyApplication>(
|
||||||
BootModule,
|
BootModule,
|
||||||
|
Loading…
Reference in New Issue
Block a user