[Instagram-Clone] JWT 인증
- -
GIthub : https://github.com/juuuuung/Instagram_clone
JWT?
내가 설명하면 말이 길어질 수 있으니 정말 좋은 글을 찾아 왔다.
jwt에 대해서는 망나니개발자님의 글을 참고 하면 좋을것 같다.
무엇을 어떻게 했는가
난 JWT와 SESSION 방식 중에 어떤걸 사용해야 할까 고민 했다.
결론적으로 JWT를 사용했으며, 그 이유는 간단하다 한번도 해본적이 없어서 경험해 보고 싶었다.
각설하고 어떻게 구현했는지 코드를 보자
(솔직히 인터넷 뒤지면서 막 따라 했다)
JWT를 Nest에서 사용하기위해서는 passport를 설치 해야한다
npm install --save @nestjs/passport passport passport-local
npm install --save-dev @types/passport-local
그리고
nest g mo auth
nest g s auth
AuthModule과 AuthService를 만들어 준다.
( Nestjs 공식 문서에서는 UserModule과 UserService까지 한다 )
// auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { appRepository } from 'src/app.repository';
@Injectable()
export class AuthService {
constructor(
private readonly appRepository: appRepository,
private readonly jwtService: JwtService,
) {}
async validateUser(userId: string, pass: string): Promise<any> {
const user = await this.appRepository.findUser(userId);
if (user[0] && user[0].userPw === pass) {
const { userPw, ...result } = user[0];
return result;
}
return null;
}
async login(user: any) {
const payload = {userId : user.userId, nickName : user.nickName, role : user.role}
return {
access_token: this.jwtService.sign(payload),
};
}
}
나는 prisma를 사용하고 Repository를 만들어서 바로 연결하고 싶었기 때문에 appRepository를 주입 해주었다
validateUser Method는 뭘 하는 아이인가 물어본다면 인증 로직이다.
AuthModule을 수정하고 가자
// server/src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { appRepository } from 'src/app.repository';
import { JwtService } from '@nestjs/jwt';
import { PrismaService } from 'src/prisma.service';
@Module({
providers: [
AuthService,
appRepository,
PrismaService,
JwtService,
],
exports: [AuthService],
})
export class AuthModule {}
export : [AuthService] 를 해주어야 AppModule에서 AuthModule를 import하고 AppController에서 AuthService를 사용 할 수 있다
지금은 이해 하려 하지말고 그냥 그렇구나 하고 넘어가도 상관 없는 말이다
이제 아까 인증 로직이 어디에 사용되는지 알아보려면
새로운 폴더와 파일을 만들어야한다
auth/strategy 폴더 생성하기
auth/strategy/local.strategy.ts 파일 생성
// server/src/auth/strategy/local.strategy.ts
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport/dist';
import { Strategy } from 'passport-local';
import { AuthService } from '../auth.service';
@Injectable()
export class LocalStrtegy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({ usernameField: 'userId', passwordField: 'userPw' });
}
async validate(userId: string, userPw: string): Promise<any> {
const user = await this.authService.validateUser(userId, userPw);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
validate함수의 기본 인자는 (username, password) 이다 변경을 원하면 super에서 바꿔주면 된다
server/src/auth/guard 폴더 생성
server/src/auth/guard/local-auth.guard.ts 파일 생성
// server/src/auth/guard/local-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}
// server/src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { JwtModule, JwtService } from '@nestjs/jwt';
import { appRepository } from 'src/app.repository';
import { PrismaService } from 'src/prisma.service';
@Module({
providers: [
AuthService,
LocalStrategy,
appRepository,
PrismaService,
JwtService
],
exports: [AuthService],
})
export class AuthModule {}
JWT
$ npm install --save @nestjs/jwt passport-jwt
$ npm install --save-dev @types/passport-jwt
import { ExecutionContext, HttpException, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { AuthGuard } from '@nestjs/passport';
import { jwtConstants } from '../constants';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
constructor(private readonly jwtService: JwtService) {
super();
}
canActivate(context: ExecutionContext): boolean {
const req = context.switchToHttp().getRequest();
const { authorization } = req.headers;
if (authorization === undefined) {
throw new HttpException('not good', 401);
}
req.user = this.validateToken(authorization.replace('Bearer ', ''));
return true;
}
validateToken(token: string) {
try {
return this.jwtService.verify(token, jwtConstants);
} catch (error) {
const errorMsgArray = [
'EXPIRED_TOKEN',
'INVALID_TOKEN',
'TOKEN_IS_ARRAY',
'NO_USER',
];
switch (error.message) {
case errorMsgArray.includes(error.message, 1):
throw new HttpException('유효하지 않은 토큰 입니다.', 401);
case errorMsgArray.includes(error.message):
throw new HttpException('토큰이 만료되었습니다.', 401);
default:
throw new HttpException('서버 오류입니다.', 401);
}
}
}
}
auth Module에 추가 해줘야 할것이 있다.
// server/src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { LocalStrtegy } from './strategy/local.strategy';
import { JwtModule } from '@nestjs/jwt';
import { jwtConstants } from './constants';
import { JwtStrategy } from './strategy/jwt.strategy';
import { appRepository } from 'src/app.repository';
import { PrismaService } from 'src/prisma.service';
@Module({
imports: [
PassportModule,
JwtModule.register({
secret: jwtConstants.secret,
signOptions: { expiresIn: '1m' },
}),
],
providers: [
AuthService,
LocalStrtegy,
JwtStrategy,
appRepository,
PrismaService,
],
exports: [AuthService],
})
export class AuthModule {}
자이제 app.controller.ts에 추가해보자
import { Controller, Post, UseGuards, Request, Body } from '@nestjs/common';
import { AuthService } from './auth/auth.service';
import { AccountDto } from './auth/DTO/Account.dto';
import { LocalAuthGuard } from './auth/guard/local-auth.guard';
@Controller('auth')
export class AppController {
constructor(private readonly authService: AuthService) {}
@UseGuards(LocalAuthGuard)
@Post('login')
async login(@Request() req) {
return this.authService.login(req.user);
}
}
localAuthGuard -> localStrategy.validate -> authService.validateUser 성공시 req에 user주입 -> authService.login(req.user)
로그인에 성공하면 payload를 넣은 apikey를 준다
글을 쓴 후
솔직하게 jwt를 어떻게 사용할지 몰라 많이 당황스러웠으며, 다른사람의 코드를 따라한것이다.
이제 nestJs 어떤 방식으로 돌아가는지 발톱만큼은 이해한것 같다
다음글은 role Gaurd에 대해 써볼 생각이다.
'🗂️ Project > 🧸 Instagram-Clone' 카테고리의 다른 글
[Instagram-Clone] 지난 6일간 (0) | 2023.01.18 |
---|---|
[Instagram-Clone] Login/Sign View Styles (0) | 2023.01.12 |
[Instagram-Clone] 시작 (0) | 2023.01.08 |
[Instagram-Clone] 로그인/가입 화면 기획 (0) | 2023.01.08 |
[Instagram-Clone] 파일 구조 (0) | 2023.01.08 |
소중한 공감 감사합니다