Hashing
하는 방법
//해시테이블을 사용할수 없게 salt를 사용한다.
const salt = randomBytes(8).toString('hex');
// salt를 포함해 해싱
const hash = (await scrpyt(password, salt, 32)) as Buffer;
// 나중에 다시 해싱할수 있도록 salt를 포함해 저장한다.
const result = salt + '.' + hash.toString('hex');
세션 설정하기
- 라이브러리 설치하기
- npm i cookie-session
- npm i @types/cookie-session
- main.ts 에 설정하기
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 쿠키 세션 사용하기
// keys의 값을 사용해 쿠키를 암호화한다.
app.use(cookieSession({
keys: ['anythingyouwant']
}))
app.useGlobalPipes(
new ValidationPipe({
whitelist: true
})
)
await app.listen(3000);
}
세션에 값을 저장하는 예시
@Get('/colors/:color')
setColor(@Param('color') color:string, @Session() session: any) {
session.color = color;
}
@Get('/colors')
getColor(@Session() session: any) {
return session.color;
}
// session의 color에 값이 저장되고 조회된다.
로그인 확인
- 특정 핸들러에 대해 로그인 되어 있지 않으면 거부
- Guard로 부른다.
AuthGuard
class AuthGuard {
// 유저가 접근 가능할시 true 리턴
// 접근 불가능할시 false 리턴
canActivate()
}
- Guard를 만들어 전체 혹은 특정 컨트롤러 혹은 특정 핸들러에 적용 가능하다.
Guard 구현하기
export class AuthGuard implements CanActivate {
// context : 들어온 요청
canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
return request.session.userId;
}
}
@Get('/whoami')
@UseGuards(AuthGuard)
whoAmI(@CurrentUser() user: User) {
return user;
}
유저 확인
- 현재 로그인한 유저가 누구인지 확인한다.
- 인터셉터, 데코레이터를 통해 구현한다.
데코레이터
@Get('/whoami')
whoAmI(@CurrentUser() user: User) {
return user;
}
- 위와 같은 custom decorator를 만들어 현재 로그인된 유저를 확인할 것이다.
- 데코레이터는 이름.decorator.ts 로 짓는다.
데코레이터 구현
export const CurrentUser = createParamDecorator(
// context : 요청의 정보를 담고 있다.
// data : decorator의 소괄호에 들어가는 값
// @CurrentUser(data) ...
(data: never, context: ExecutionContext) => {
// http request 가져오기
const request = context.switchToHttp().getRequest();
return request.currentUser;
}
)
- 데코레이터는 DI ( Injection ) 에 접근이 불가능해
인터셉터를 같이 사용한다.
인터셉터 구현
- request.currentUser 를 지정해 데코레이터에서 사용할수 있도록 한 것이다.
@Injectable()
export class CurrentUserInterceptor implements NestInterceptor {
constructor(private usersService: UsersService) {}
async intercept(context: ExecutionContext, handler: CallHandler) {
const request = context.switchToHttp().getRequest();
const { userId } = request.session || {};
// userId가 있으면, currentUser으로 user를 초기화한다.
if(userId) {
const user = await this.usersService.findOne(userId);
request.currentUser = user;
}
return handler.handle();
}
}
- 인터셉터 사용하기
- 컨트롤러단에 인터셉터 사용
- 모듈에 provider로 추가하기
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UsersController],
providers: [UsersService, AuthService, CurrentUserInterceptor]
})
export class UsersModule {}
- 이후 UseInterceptors를 사용한다.
@UseInterceptors(CurrentUserInterceptor)
export class UsersController
- APP_INTERCEPTOR 사용하기 ( 모든 요청에 인터셉트 )
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UsersController],
providers: [UsersService, AuthService, {
provide: APP_INTERCEPTOR,
useClass: CurrentUserInterceptor
}]
})