2025. 1. 27. 16:27ㆍ개발/Node
10.6 패스포트와 세션을 사용한 인증 구현
2025.1.27
- 서버에서 인증을 하고 해당 정보를 서버의 특정공간에 저장.(세션 이용)
- 쿠키는 세션을 찾는 정보만 저장(세션의 아이디값) 중요 정보는 세션에 모두 넣음.
- 세션은 서버의 자원을 사용하여 서버에 부하를 주지만 위조,변조,탈취가 불가능하여 보안적임.
- 가드하나로 로그인과 인증 모두 사용했지만 가드 두개와 인증 처리를 하기위한 파일을 여러개 만들것.
- 로그인에 사용할 가드.
- 인증 로직 구현 부분은 패스포트 라는 인증 로직을 쉽게 분리해서 개발하는 라이브러리 사용
- 패스포트 사용시 인증 로직은 스트래티지 파일을 생성해서 사용.
- 패스포트는 인증 로직 수행을 담당하는 클래스를 의미함.
- 다양한 인증을 위한 스트래티지 패키지를 같이 설치해 인증을 쉽게 구현가능.
- 가드 안에 인증 로직을 두는것이 아닌 인증로직을 처리하는 별도의 스트래티지 파일 작성
- id, password 주었을때 올바른 정보인지 판단하는로직, 쿠키에서 값을 읽어 인증을 ㅟ한 올바른 데이터가 있는지 검증하는 로직 의미
- 세션에서 데이터를 읽어오고 저장하므로 세션에 데이터 저장하고 읽어올 세션 시리얼라이저(session serializer) 파일도 필요함.
- 가드 패스포트 스트래티지, 세션 시리얼라이저가 서로 협력하여 사용자 신원을 확ㅇ니하고 이증 정보를 저장하고 읽어와서 다시 인증하는 작업을 함. 역할 분담이 잘되어 있어서 유지보수에 유리함.
10.6.1 라이브러리 설치 및 설정
(1) passport 라이브러리 설치
passport-local : username 과 password 로 인증전략 모듈
세션 저장에는 express-session 사용
개발할때 유용하므로 개발 환경 패키지를 설치하는 -D 옵션을 주어 설치함.
npm i @nestjs/passport passport passport-local express-session
npm i -D @types/passport-local @types/express-session
(2) 세션을 사용하려면 main.ts 파일에 설정 추가
📌 src/main.ts
// 로그인 인증을 위한 세션, passport 라이브러리 임포트
import * as session from 'express-session'
import * as passport from 'passport'
//(생략)
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// session 설정
app.use(
session({
secret: 'very-important-secret', // 세션 암호화 키
resave: false, // 세션을 항상 저장할지 여부
// 세션 저장되기 전 초기화 되지 않은 상태로 세션을 미리 저장
saveUninitialized: false,
cookie: {maxAge: 3600000} // 쿠키 유효시간 1시간
})
)
// passport 시작, session 선언
app.use(passport.initialize())
app.use(passport.session())
10.6.2 로그인과 인증에 사용할 가드 구현
로그인에 사용할 가드와 로그인후 인증에 사용할 가드를 별개로 생성하여 사용
loginAuthGuard 는 HTTp 요청을 받은 email 과 password 정보로 유효한 user 정보가 있는지 확인해 유효할 경우 유저 정보를 세션에 저장.
AuthenticatedGuard 는 HTTP 요청에 잇는 쿠키를 찾아 쿠키에 있는 정보로 세션을 학인해 로그인이 완료된 사용자인지 판별
- LoginAuthGuard 와 AuthenticatedGuard 가드를 auth.guard.ts 에 추가

/// src/auth/auth.guard.ts
// Guard 를 사용하기 위한 임포트
import { CanActivate, ExecutionContext, Injectable, Request} from '@nestjs/common'
// 패스포트 사용하는 AuthGuard 임포트
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from './auth.service'
@Injectable()
// AuthGuard 상속
export class LocalAuthGuard extends AuthGuard('local') {
async canActivate(context: any): Promise<boolean> {
const result = (await super.canActivate(context)) as boolean
// 로컬 스트래티지 실행
const request = context.switchToHttp().getRequest()
// 세션 저장
await super.logIn(request)
return result
}
}
@Injectable()
export class AuthenticatedGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean{
const request = context.switchToHttp().getRequest()
// 세션에서 정보를 읽어서 인증 확인
return request.isAuthenticated()
}
}
- 패스 포트 인증에 가드를 사용할수 있도록 감싸둔 AuthGuard 를 제공하는 라이브러리
- 패스포트는 인증로직을 스트래티지 개념으로 구현.
- 이외에 스트레티지로 passport-jwt 와 passport-google-oauth20 이 있음.
- 가드를 사용하려면 canActivate를 구현
- AuthGuard 상속 하여 super.canActivate() 에 서 passport-local 로직을 구현할 메서드 실행함.
- local.startagy.ts 파일이 localStrategy 클래스 생성한후 valdiate() 메서드 구현
- super.logIn()에서 로그인 처리, 세션저장함. 세션에서 꺼내오는 방법은 session.serializaer.ts 파일에서 작성
- AuthenticatedGuard 가 로그인 후 인증되었는지 확인할때 사용.
- 세션에 덷이터를 저장하고 돌려주는 응답값에 connect.sid 라는 이름의 쿠키를 만듬.
- 이후 요청에 해당 쿠키값을 같이 전송하면 세션에 있는 값을 읽어 인증 여부를 확인 할떄 사용함.
10.6.3 세션에 정보를 저장하고 읽는 세션 시리얼라이저 구현
(1) request.isAuthenticated() 함수가 세션에서 정보를 읽어옴.
import { Injectable } from "@nestjs/common";
import { PassportSerializer } from "@nestjs/passport";
// userService 주입 -> 유저정보를 검증
import { UserService } from "src/user/user.service";
@Injectable()
export class SessionSerializer extends PassportSerializer {
constructor(private userService: UserService){
super();
}
// 세션에 유저의 이메일 정보 저장
serializeUser(user: any, done: (err:Error, user:any) => void):any {
done(null,user.email) // 세션에 저장할 정보
}
// 세션에서 정보를 꺼내올떄 사용
async deserializeUser(
payload: any,
done: (err: Error, payload: any) => void,
): Promise<any> {
const user = await this.userService.getUser(payload)
// 유저 정보가 없는경우 done()함수에 에러 전달
if(!user) {
done(new Error('No User'), null)
return
}
const { password, ...userInfo} = user
done(null,userInfo)
}
}
SessionSerializer : 로그인 성공후 사용자정보를 세션에 저장. 이메일(최소한의 정보)만 추출하여 세션에 저장. 이후 요청에서 세션정보를 이용하여 사용자 정보를 복원함.
serializeUser 함수가 이메일을 세션에 저장하는 작업 완료후 그결과를 Passport 에 알림.
user 정보는 LocalAuthGuard 의 canActive() 메서드 의 super.logIn(request)를 호출 할때 내부적으로 request에 있는 user 정보를 꺼내서 전달하면서 serializeUser 실행done(err:Error, user :any): Passport.js 에서 비동기 작업의 결과를 처리하기 위해 사용하는 콜백 , err 는 Error 타입의 객체임. 결과 void 이므로 done 은 어떤 값도 반환 하지 않음.
(user: any ..)
: user 는 매개변수 이름. 로그인전략( local,google,facebook) 성공시 전달해주는 사용자 정보를 의미함!! LocalAuthGuard 사용시 valildateUser 메소드에서 반환된 유저정보가 serializeUser 함수의 user인자로 전달됨.getPassportInstance() : 패스포트 인스턴스를 가져옴, 패스포트 인스턴스의 데이터가 필요한 경우 사용
deserializeUser() : 인증되었는지 세션에 있는 정보로 검증할때
payload(세션에서 꺼내온값.전달되는 데이터의 핵심 부분 ) : deserializeUser 함수에서 세션에 저장된 사용자 식별 정보(이메일)를 전달 받아 해당 사용자의 정보를 조회하고 복원하는데 사용하는 값.

10.6.4 email,password 인증 로직이 있는 LocalStrategy 파일 작성
- 인증 방법이 다양함. 패스포트에서 strategy(인증전략) 이라는 별개의 패키지로 분리해 담음.
- id, password 로 인증하는 기능은 passport-local 패키지에서 제공함.
인증방법 | 패키지 | 설명 |
---|---|---|
Local | passport-local | 유저명, 패스워드를 사용 |
OAuth | passport-oauth | 구글,페이스북 등 외부 서비스에서 인증 |
SAML | passport-saml | SAML 신원제공사에서 인증, OneLogin, Okta |
JWT | passport-jwt | JSON web token 인증 |
AWS Cognito | passport-cognito | AWS Cognito user pool 인증 |
LDAP | passport-ldapauth | LDAP 디렉터리 사용 |
(1) email, password 인증 로직이 있는 localStrategy 파일 작성
//auth/local.strategy.ts
//auth/local.strategy.ts
import { Injectable } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy } from "passport-local";
import { AuthService } from "./auth.service";
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
// 1. PassportStrategy 믹스 인
constructor( private authService: AuthService) {
// 기본값이 username 이므로 email 로 변경함.
super({usernameField :'email'})
}
// 유저 정보의 유효성 검증
async validate(email: string, password: string) : Promise<any> {
const user = await this.authService.validateUser(email,password)
if (!user) {
return null // null -> 404 에러
}
return user // user 정보 반환
}
}
PassportStrategy(Strategy) : 믹스인
컴포는트를 재사용할 때 상속을 많이 사용하지만 해당 클래스의 모든것을 재사용해야하는 불편함. 클래스의 일부만 확장하고 싶을 때는 믹스인 을 사용
🤔 믹스인(mixin) / 트레잇(trait)
클래스에 새로운 기능을 추가하기 위해, 필요한 메서드를 가지고 있는 작은 클래스들을 결합해 기능을 추가하는 방법local-strategy 에는 인증시 사용하는 필드명이 username, password 로 정해져있으므로 usernameField 이름을 email 로 바꾸어줌.
validate() 메서드에서는 전달한 email과 password 가 올바른지 검증함.(이미 있는 authSErvice 의 validateUser() 사용 )
10.6.5 auth.module.ts 에 설정 추가
만들어둔 LocalStrategy, SessionSerializer 를 다른 클래스에서 사용하도록 프로바이더 등록, passportModule에 세션을 추가 등록
// auth.module.ts
// Passport, serializer , local strategy 추가
import { PassportModule } from '@nestjs/passport';
import { SessionSerializer } from './session.serializer';
import { LocalStrategy } from './local.strategy';
console.log(chalk.red('AuthModule Start[[[인증]]]]'))
@Module({
imports: [
UserModule,
PassportModule.register({session: true}),
],
providers: [
AuthService,
LocalStrategy,
SessionSerializer
],
controllers: [AuthController]
})
- PassportModule 의 기본설정은 세션 설정이 false 로 되어있어서 true 로 설정.
- LocalStrategy ,SessionSerializer 프로바이더 등록 필요 다른데서 주입하지 않아도 프로바이더 등록안하면 클래스를 찾지 못해 에러남.
10.6.6. 테스트
// auth.controller.ts
// 가드 사용 임포트
import { AuthenticatedGuard, LocalAuthGuard, LoginGuard } from './auth.guard';
// Login 3. 가드, 세션, 쿠키 사용
@UseGuards()
@Post('login3')
login3(@Request() req ) {
return req.user
}
@UseGuards(AuthenticatedGuard)
@Get('test-guard2')
testGuardWithSession(@Request() req){
return req.user
}
}
### USER login 가드 테스트 ( cookie 기록 )
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"email":"test1@grkcon.com",
"password":"grkcon2025!"
}' \
-c cookies.txt \
http://localhost:3000/auth/login3
- 틀린 패스워드로 하면 401 에러가 난다. (auth.service validateUser() 동작 )
- 인증이 성공하면 유저정보가 나온다.
- 서버 재시작 하면 세션은 초기화 됨.
10.6.7 로그인과 세션 저장까지 순서

'개발 > Node' 카테고리의 다른 글
# [node] 웹소켓을 사용한 실시간 채팅 구현 (0) | 2025.02.02 |
---|---|
# [node] 11. OAuth 를 사용한 구글 로그인 인증 (0) | 2025.01.28 |
# [NestJS] 사용자 인증 모듈 생성 및 회원 가입하기 [2단계] (0) | 2025.01.27 |
#[node] 환경변수 2탄 (0) | 2025.01.23 |
#[node] 회원 가입 로그인 (0) | 2025.01.23 |