일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- JPA스터디
- 코테공부
- nestjs스터디
- 프로그래머스
- 스프링 공부
- 스프링공부
- Kafka
- nestjs공부
- Flutter
- Axon framework
- 스프링부트
- K8S
- 자료구조공부
- DDD
- JPA예제
- 플러터 공부
- 기술공부
- JPA 공부
- 플러터 개발
- 카프카
- 알고리즘공부
- 자바공부
- JPA
- nestjs
- 스프링부트공부
- JPA공부
- 스프링
- querydsl
- 기술면접공부
- 코테준비
- Today
- Total
DevBoi
[NestJs] AuthGuard 전략 복수개 적용하기 본문
오늘은 AuthGuard를 이용하여, 해당 가드를 적용할건데
각기 다른 정책으로 관리가 되게 개발을 할 것이다.
쉽게 얘기하면, 한개는 일반 사용자인지, 즉 auth bearer token으로 요청을 하는지
또 한개는 해당 사용자이지만, 사업가의 authCode인지를 체크하는 것이다.
적용한 코드를 참고 바란다.
1.패키지 구조
2.auth-guard.ts
import { ExecutionContext, Injectable } from "@nestjs/common";
import { AuthGuard as NestAuthGuard } from "@nestjs/passport";
import { Observable } from "rxjs";
@Injectable()
export class JwtAuthGuard extends NestAuthGuard('member'){
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
return super.canActivate(context)
}
}
3.auth-module
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { JwtStrategy } from './passport.jwt.strategy';
import { MemberService } from 'src/member/service/member.service';
import { MemberRepostiory } from 'src/member/repository/member.repository';
import { Member } from 'src/member/entities/member.entity';
import { CorpJwtStrategy } from './passport.jwt.corp.strategy';
@Module({
imports: [
PassportModule.register({defaultStrategy: 'jwt'}),
TypeOrmModule.forFeature([Member]),
JwtModule.register({
secret: 'sadfasdfasfasdfdasfasfdads',
signOptions: {expiresIn: '300s'},
}),
PassportModule
],
exports: [TypeOrmModule],
controllers: [AuthController],
providers: [AuthService, MemberService,JwtStrategy,MemberRepostiory,CorpJwtStrategy]
})
export class AuthModule {}
4. auth.service
import { HttpException, HttpStatus, Injectable, UnauthorizedException } from '@nestjs/common';
import { UserDTO } from '../user/dto/auth-user.dto';
import { User } from '../user/entities/user.entity';
import { UserService } from '../user/user.service';
import * as bcrypt from 'bcrypt';
import { Payload } from './payload.interface';
import { JwtService } from '@nestjs/jwt';
import { MemberReqDto } from 'src/member/dto/member.req.dto';
import { MemberService } from 'src/member/service/member.service';
import { Member } from 'src/member/entities/member.entity';
import { MemberRepostiory } from 'src/member/repository/member.repository';
@Injectable()
export class AuthService {
constructor(
private memberService: MemberService,
private jwtService: JwtService
){}
//회원가입
async registerUser(memberReqDto: MemberReqDto): Promise<Member> {
await this.transformPassword(memberReqDto);
return this.memberService.save(memberReqDto);
}
//로그인
async validateUser(memberReqDto: MemberReqDto): Promise<{accessToken: string} | undefined> {
const member = await this.memberService.findOne(memberReqDto.id);
const validatePassword = await bcrypt.compare(memberReqDto.password,member.password);
if(!member || !validatePassword) {
throw new UnauthorizedException();
}
const payload: Payload = { id: memberReqDto.id, password: memberReqDto.password};
return {
accessToken: this.jwtService.sign(payload)
};
}
async tokenValidateUser(payload: Payload): Promise<Member| undefined> {
return this.memberService.findOne(payload.id);
}
async corptokenValidateUser(payload: Payload): Promise<Member| undefined> {
return this.memberService.findOne(payload.id);
}
async transformPassword(member: MemberReqDto): Promise<void> {
member.password = await bcrypt.hash(
member.password, 10,
);
return Promise.resolve();
}
}
4. passport-jwt-corp stragety
import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy,ExtractJwt,VerifiedCallback } from "passport-jwt";
import { AuthService } from "./auth.service";
import { Payload } from "./payload.interface";
@Injectable()
export class CorpJwtStrategy extends PassportStrategy(Strategy,'corp'){
constructor(private authService : AuthService ){
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration : true,
secretOrKey: 'sadfasdfasfasdfdasfasfdads'
})
}
async validate(payload: Payload, done: VerifiedCallback): Promise<any> {
console.log('corp')
const user = await this.authService.corptokenValidateUser(payload);
console.log(user);
//authCode가 10이면 사업자가 아니라 일반 사용자라고 가정한다.
if(!user) {
throw new UnauthorizedException({message: 'user does not exist'});
}
if(user.authCode==10){
throw new UnauthorizedException({message: 'this is not corp user'});
}
return user;
}
}
5. passport.jwt.stragety
import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy,ExtractJwt,VerifiedCallback } from "passport-jwt";
import { AuthService } from "./auth.service";
import { Payload } from "./payload.interface";
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy,'member'){
constructor(private authService : AuthService ){
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration : true,
secretOrKey: 'sadfasdfasfasdfdasfasfdads'
})
}
async validate(payload: Payload, done: VerifiedCallback): Promise<any> {
const user = await this.authService.tokenValidateUser(payload);
console.log(user);
if(!user) {
throw new UnauthorizedException({message: 'user does not exist'});
}
return user;
}
}
6. payload.interface
export interface Payload {
id: string;
password: string;
}
7. auth-controller
import { Body, Controller, Get, Post, Req, Res, UseGuards } from '@nestjs/common';
import { Request, Response } from 'express';
import { AuthService } from './auth.service';
import { UserDTO } from '../user/dto/auth-user.dto';
import { JwtAuthGuard } from './auth-guard';
import { ApiTags, ApiOperation, ApiResponse, ApiQuery, ApiParam, ApiBody } from '@nestjs/swagger';
import { CreateUserDto } from 'src/user/dto/create-user.dto';
import { MemberReqDto } from 'src/member/dto/member.req.dto';
import { CorpJwtAuthGuard } from './auth-corp-guard';
@ApiTags('auth') // (옵션) 태그 추가
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
@ApiOperation({ summary: '회원 가입' }) // (옵션) API 동작 설명
@ApiBody({
description: 'User registration data',
type: MemberReqDto, // UserDTO 타입 지정
})
@Post('/register')
async registerAccount(@Body() memberReqDto: MemberReqDto): Promise<any> {
return await this.authService.registerUser(memberReqDto);
}
@ApiOperation({ summary: '유저 로그인' }) // (옵션) API 동작 설명
@Post('/login')
async login(@Body() MemberReqDto: MemberReqDto, @Res() res: Response): Promise<any> {
const jwt = await this.authService.validateUser(MemberReqDto);
res.setHeader('Authorization', 'Bearer ' + jwt.accessToken);
return res.json(jwt);
}
//샘플 동작 모듈 헤더에 첨부된 accesskey가 올바르지 않으면, 오류가 발생한다.
@ApiOperation({ summary: '유저 인증' }) // (옵션) API 동작 설명
@Post('/authenticate')
@UseGuards(JwtAuthGuard)
isAuthenticated(@Req() req: Request): any {
return "success";
}
@ApiOperation({ summary: '유저 인증' }) // (옵션) API 동작 설명
@Post('/authenticate-corp')
@UseGuards(CorpJwtAuthGuard)
isAuthenticatedcorp(@Req() req: Request): any {
return "corp_success";
}
}
쉽게 동작과정을 살펴보면 아래와 같다.
1. authcontroller로 회원가입을 한다.
2. authcontroller로 로그인을 한다-> 이때 회원정보의 유효성을 검증한다.
검증후에, 해당 관련 비밀번호와 아이디가 맞다면, 해당 payload에 값을 실어서 access-token을 발급한다.
3. 해당 authenticate나 -corp를 호출하게 되면,
4.해당 authguard로 인해, 각 전략의 밸리데이트 메소드로 가게 되고, 해당 메소드에서 예외를 던지거나 처리를 마무리하여 리턴하고 메소드의 로직이 돈다.
<정리>
JwtAuthGuard , CorpJwtAuthGuard 이 두개는 해당 각 가드의 이름을 별도로 설정하여,
해당 가드를 맞게끔 따라가도록 설정을 해주었기 때문에 분기 처리가 가능하다.
대부분 여러가지 역할이 있을 것이고, 해당 역할에 따라서 다르게 인증 처리를 할 것인데
해당과 같이 관리를 하게 되면 편하게 두가지 분기처리로 나눠서 개발을 진행할 수 있다.
'Develop > [NestJs]' 카테고리의 다른 글
[NestJs] TypeOrm 0.2 -> 0.3 버전 변경 (0) | 2023.08.20 |
---|---|
[NestJs] QueryBuilder (0) | 2023.07.09 |
[NestJs] 매핑 테이블 엔티티 생성 및 사용 (0) | 2023.07.03 |
[NestJs] 암호화 모듈 (0) | 2023.07.03 |
[NestJs] Custom Pipeline 만들어보기 (0) | 2023.07.02 |