Web개발에서
미들웨어
는라우트핸들러
가 클라이언트의 요청을 처리하기전, 수행되는 컴포넌트를 의미한다라우트핸들러란 Nest.js와같은 프레임워크에서 요청을 처리하는 엔드포인트마다 동작을 수행하는 컴포넌트 (@Get등등..)
쿠키파싱
: 쿠키를 파싱해와서 쉬운 데이터 구조로 변경해준다.세션관리
: 세션 쿠키를 찾은후, 해당 쿠키에대한 세션상태를 조회후 요청에 세션정보를 추가해준다인증/인가
: 사용자가 서비스에 접근가능한 권한이 있는지 확인, Nest에선 Guard
를 권장한다본문
: 본문은 POST,PUT요청으로 들어오는 JSON형태의 타입뿐만아니라 File과같은 데이터도 있다, 이 데이터를 유형에 따라 읽고 해석한후 파라미터에 넣는 작업인가(Authorization)은 인증을 통과한 유저가 요청한 기능을 사용할 권한이 있는지를 판별하는 것을 말한다. 퍼미션,롤,ACL과 같은 개념을 사용하여 유저가 가지고 있는 속성으로 리소스 사용을 허용할 지 판별한다.
보통 인증과 인가가 실패할 경우의 응답코드는 401과 403이다
가드는
CanActivate
인터페이스를 구현해야한다.canActivate 함수는
ExecutionContext
인스턴스를 인자로 받고,ExcutionContext
는ArgumentsHost
를 상속받는데 요청,응답에대한 정보를 가지고 있다
우리는 HTTP로 기능을 제공하기때문에switchToHttp()
함수를 사용하여 필요한 정보를 가져올 수 있다.
이렇게 얻은 정보를 내뷰 규칙으로 평가하는 validateRequest함수를 통해 인가를 진행한다
컨트롤러나 메소드쪽에서 적용하고자 한다면
@UseGuards(AuthGuard)
와 같이 사용한다(데코레이터)
AuthGuard 인스턴스 생성은 Nest가 대신 해준다.
만약, 여러 종류의 가드를 적용하고 싶다면 쉼표로 이어 선언하면 된다
사용자의 정보를 보호하기 위해서는, 서버에 접속하는 클라이언트(유저)가 주인인지 확인을 하는 절차를 거쳐야한다,
사용자가 아이디와 비밀번호로 로그인을 한다면 로그아웃을 할 때 까지 해당 클라이언트가 가진 권한 내에서 서비스를 사용할 수 있다.
즉, 사용자가 가진 정보를 조회하고 변경할 수 있게된다.
세션은 로그인에 성공한 유저가 서비스를 사용하는 동안 저장하고 있는 유저의 정보이다
서버는 세션을 생성하고나서 세션을 DB에 저장하고, 이후 사용자의 요청에 포함된 세션 정보가 세션 DB에 저장되어 있는지 확인한다.
세션방식의 단점은 공격자가 브라우저에 저장된 데이터를 탈취할 수 있다는것.
탈취된 세션을 이용하면 해당 사용자인것 처럼 서버에 접근이 가능하다
이를 방지하기 위해 https로 암호화된 통신을 하거나 세션에 유효시간을 정해둔다.
세션이 사용자 인증 정보를 서버에 저장하는 방식인 반면, 토큰은 사용자가 로그인 했을 때 서버에서 토큰을 생성한 후, 전달하고 따로 저장소에는 저장을 하지 않는 방식
이후 요청에 대해 클라이언트가 전달한 토큰에 대해 검증을 수행한다,
JWT
를 제일 많이사용
회원 가입 요청에 포함된 이메일에는 다음 링크가 있엇다
const url =
`${baseUrl}/users/email-verify?
signupVerifyToken=${signupVerifyToken}`;
signupVerifyToken
은 회원 가입시에 서버에서 발급한 임의의 문자열로 메일사용자에게 유일한 값이다, 버튼을 누르면 POST로 email-verify엔드포인트로 요청을 보내는데 이 요청을 처리하는것이 이메일 인증처리
Auth등록
Module
import { Module } from '@nestjs/common'; import { AuthService } from './auth.service'; @Module({ imports: [], providers: [AuthService], exports: [AuthService], }) export class AuthModule {}
Service
import { Inject, Injectable } from '@nestjs/common'; import { ConfigType } from '@nestjs/config'; import authConfig from 'src/config/authConfig'; import * as jwt from 'jsonwebtoken'; interface User { id: string; name: string; email: string; } @Injectable() export class AuthService { constructor( @Inject(authConfig.KEY) private config: ConfigType<typeof authConfig>, // ) {} login(user: User) { const payload = { ...user }; return jwt.sign(payload, this.config.JWT_SECRET, { expiresIn: '1d', audience: 'example.com', issuer: 'example.com', }); } }
Auth모듈과 서비스를 완성후 이메일인증을요청
JWT 발급에 사용한 비공개 클레임들과 등록된 클레임이 포함된것을 확인가능. lat -> 발급시간(자동 생성)
async login(email: string, password: string): Promise<string> {
// 1. email, password 가진 유저가 db에있다면 처리, 없으면 에러
const user = await this.usersRepository.findOne({
where: { email: email, password: password },
});
if (!user) {
throw new NotFoundException('유저가 존재하지 않습니다');
}
// 2. JWT를 발급해 전달
return this.authService.login({
id: user.id,
name: user.name,
email: user.email,
});
}