작성
·
235
·
수정됨
0
// is-public.const.ts
export enum IsPublicEnum {
ISPUBLIC = 'ISPUBLIC',
ISREFRESHTOKEN = 'ISREFRESHTOKEN',
}
// is-public.decorator.ts
import { SetMetadata } from '@nestjs/common';
import { IsPublicEnum } from '../const/is-public.const';
export const ISPUBLIC_KEY = 'is_public';
export const IsPublic = (status: IsPublicEnum) =>
SetMetadata(ISPUBLIC_KEY, status);
// bearer-token.guard.ts
@Injectable()
export class BearerTokenGuard implements CanActivate {
constructor(
private readonly authService: AuthService,
private readonly usersService: UsersService,
public readonly reflector: Reflector,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const req = context.switchToHttp().getRequest();
const requiredPublic = this.reflector.getAllAndOverride(ISPUBLIC_KEY, [
context.getHandler(),
context.getClass,
]);
if (requiredPublic) {
req.requiredPublic = requiredPublic;
}
if (requiredPublic === IsPublicEnum.ISPUBLIC) {
return true;
}
const rawToken = req.headers['authorization'];
if (!rawToken) throw new UnauthorizedException('토큰이 없습니다!');
const token = this.authService.extractTokenFromHeader(rawToken, true);
const result = await this.authService.verifyToken(token);
const user = await this.usersService.getUserByEmail(result.email);
req.user = user;
req.token = token;
req.tokenType = result.type;
return true;
}
}
추가된 코드
if (requiredPublic) {
req.requiredPublic = requiredPublic;
}
requiredPublic 있을때만 req에 담아줌.
추가된 코드
if (requiredPublic === IsPublicEnum.ISPUBLIC) {
return true;
}
IsPublic일때만 return true 즉, ISREFRESHTOKEN 일때는 아래 로직들이 정상적으로 실행됨.
// bearer-token.guard.ts
@Injectable()
export class AccessTokenGuard extends BearerTokenGuard {
async canActivate(context: ExecutionContext): Promise<boolean> {
await super.canActivate(context);
const req = context.switchToHttp().getRequest();
if (
req.requiredPublic === IsPublicEnum.ISPUBLIC ||
IsPublicEnum.ISREFRESHTOKEN
) {
return true;
}
if (req.tokenType !== 'access') {
throw new UnauthorizedException('Access Token이 아닙니다.');
}
return true;
}
}
추가된 코드
if (req.requiredPublic === IsPublicEnum.ISPUBLIC || IsPublicEnum.ISREFRESHTOKEN) {
return true;
}
req.requiredPublic이 ISPUBLIC이거나 ISREFRESHTOKEN이면 return true로 global accessTokenGuard return true로 빠져나옴.
// bearer-token-guard.ts
@Injectable()
export class RefreshTokenGuard extends BearerTokenGuard {
async canActivate(context: ExecutionContext): Promise<boolean> {
await super.canActivate(context);
const req = context.switchToHttp().getRequest();
if (req.tokenType !== 'refresh') {
throw new UnauthorizedException('Refresh Token이 아닙니다.');
}
return true;
}
}
변경 사항 없음. 왜냐하면 위에서 정상적으로 refreshToken을 verify하고 req에 값이 담겼기 때문에 RefreshTokenGuard가 정상적으로 실행 되어야함.
auth.controller에 적용하기
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@IsPublic(IsPublicEnum.ISREFRESHTOKEN)
@Post('token/access')
@UseGuards(RefreshTokenGuard)
postTokenAccess(@Headers('authorization') rawToken: string) {
...
}
@IsPublic(IsPublicEnum.ISREFRESHTOKEN)
@Post('token/refresh')
@UseGuards(RefreshTokenGuard)
postTokenRefresh(@Headers('authorization') rawToken: string) {
...
}
@IsPublic(IsPublicEnum.ISPUBLIC)
@Post('login/email')
@UseGuards(BasicTokenGuard)
postLoginEmail(@Headers('authorization') rawToken: string) {
...
}
@IsPublic(IsPublicEnum.ISPUBLIC)
@Post('register/email')
postRegisterEmail(@Body() body: RegisterUserDto) {
...
}
}
답변 2
1
0
안녕하세요 혹시 AccessTokenGuard를 전역적으로 지정해준 상태에서
@isPublic , @UseGuards(RefreshTokenGuard) 어노테이션이 적용된 api가 리프레쉬가드를 못타는 문제 때문에 코드 수정하신거 맞으신가요?
😃