Angular 에서 일반적으로 interceptor 는 프론트엔드단에서 관리합니다.
pages 폴더와 같은 경로에 interceptor 폴더 생성 및 이름은 상황에 맞게 설정합니다.
import {
CanActivate,
ExecutionContext,
HttpException,
Injectable,
UnauthorizedException,
Logger,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { PrismaService } from '../../../prisma/prisma.service';
import { AuthUtil } from '../auth-util.service';
import { AccessTokenType } from '@namdorang/interface';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private readonly authUtil: AuthUtil,
private readonly prismaService: PrismaService
) {}
canActivate(
context: ExecutionContext
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest(); // Http 요청을 중간에 가로 채기
// 인증 정보 확인을 위해 변수에 할당
const header = request.headers;
const authorization = header.authorization; // authoriztion 이 없음!! 왜?
Logger.log(header);
// 국제 표준 형식 : Authorization: <type> <credentials>
if (!authorization) {
throw new UnauthorizedException('사용자 정보를 찾을 수 없습니다.');
}
// <type> 타입 이름 => Bearer
if (!authorization.startsWith('Bearer ')) {
throw new UnauthorizedException('사용자 정보를 찾을 수 없습니다.');
}
// <credentials> => random string
const token = authorization.split(' ')[1];
if (!token) {
throw new UnauthorizedException('사용자 정보를 찾을 수 없습니다.');
}
let id;
try {
const payload = this.authUtil.verifyToken<AccessTokenType>(token);
if (!payload.id) {
throw new UnauthorizedException('유효하지 않은 토큰입니다.');
}
id = payload.id;
} catch (e) {
throw new HttpException('사용할 수 없는 토큰입니다.', 498);
}
const admin = this.prismaService.admin.findUnique({ where: { id } });
if (!admin) {
throw new UnauthorizedException('유효하지 않은 토큰입니다.');
}
request.user = admin; // http header 에 인증 정보를 담기
return true;
}
}
interceptor 내부 코드 모습입니다
jwt bearer 토큰을 활용하였습니다.
자세한 설명은 주석을 참고해주세요.
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import {
provideRouter,
withEnabledBlockingInitialNavigation,
} from '@angular/router';
import { appRoutes } from './app.routes';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { HttpInterceptorImpl } from './interceptors/http-interceptor'; // interceptor
import { ToastService } from '../../../common/src';
import { NgxsModule } from '@ngxs/store'; // store
import { AdminStore } from './store/auth.store'; // store
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(appRoutes, withEnabledBlockingInitialNavigation()),
importProvidersFrom(HttpClientModule, NgxsModule.forRoot([AdminStore])),
{ provide: HTTP_INTERCEPTORS, useClass: HttpInterceptorImpl, multi: true },
ToastService,
],
};