01. 준비하기
- 모듈 설치
npm install @nestjs/passport passport passport-kakao passport-naver-v2 passport-google-oauth20
- 카카오 디벨로퍼
- 네이버 디벨로퍼
https://developers.naver.com/main/
- 구글 클라우드 플랫폼 콘솔
https://console.cloud.google.com/
==> 모듈 설치와 세개의 플랫폼 설정을 해준다.
02. 사용하기
- guard
1. google-auth.guard.ts
import { AuthGuard } from '@nestjs/passport';
import { ExecutionContext, Injectable } from '@nestjs/common';
@Injectable()
export class GoogleAuthGuard extends AuthGuard('google') {
constructor() {
super();
}
handleRequest<TUser = any>(
err: any,
user: any,
info: any,
context: ExecutionContext,
status?: any,
): TUser {
// 에러
if (err || !user) {
throw err;
}
return user;
}
}
2. kakao-auth.guard.ts
import { AuthGuard } from '@nestjs/passport';
import { ExecutionContext, Injectable } from '@nestjs/common';
@Injectable()
export class KakaoAuthGuard extends AuthGuard('kakao') {
constructor() {
super();
}
handleRequest<TUser = any>(
err: any,
user: any,
info: any,
context: ExecutionContext,
status?: any,
): TUser {
// 에러
if (err || !user) {
throw err;
}
return user;
}
}
3. naver-auth.guard.ts
import { AuthGuard } from '@nestjs/passport';
import { ExecutionContext, Injectable } from '@nestjs/common';
@Injectable()
export class NaverAuthGuard extends AuthGuard('naver') {
constructor() {
super();
}
handleRequest<TUser = any>(
err: any,
user: any,
info: any,
context: ExecutionContext,
status?: any,
): TUser {
// 에러
if (err || !user) {
throw err;
}
return user;
}
}
==> Guard를 통해 컨트롤러 단에 도달하기 전에 안전하지 않은 요청을 효과적으로 차단할 수 있다.
- strategy
1. google.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-google-oauth20';
import { AuthService } from '../auth.service';
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
constructor(private readonly authService: AuthService) {
super({
clientID: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
callbackURL: '/auth/google/callback',
scope: ['email', 'profile'],
});
}
async validate(
accessToken: string,
refreshToken: string,
profile: any,
done: any,
): Promise<any> {
// profile에서 정보 추출
const email = profile._json.email;
const nickname = profile._json.name;
const provider = profile.provider;
// user 정보 확인
const exUser = await this.authService.validateUser(email);
if (exUser) {
const token = await this.authService.getToken({ userId: exUser.userId });
return token;
}
if (exUser === null) {
const newUser = await this.authService.create({ email, nickname, provider });
const token = await this.authService.getToken({ userId: newUser.userId });
return token;
}
}
}
2. kakao.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-kakao';
import { AuthService } from '../auth.service';
@Injectable()
export class KakaoStrategy extends PassportStrategy(Strategy, 'kakao') {
constructor(private readonly authService: AuthService) {
super({
clientID: process.env.KAKAO_ID,
callbackURL: '/auth/kakao/callback',
});
}
async validate(
accessToken: string,
refreshToken: string,
profile: any,
done: any,
): Promise<any> {
// profile에서 정보 추출
const email = profile._json.kakao_account.email;
const nickname = profile.displayName;
const provider = 'kakao';
// user 정보 확인
const exUser = await this.authService.validateUser(email);
if (exUser) {
const token = await this.authService.getToken({ userId: exUser.userId });
return token;
}
if (exUser === null) {
const newUser = await this.authService.create({ email, nickname, provider });
const token = await this.authService.getToken({ userId: newUser.userId });
return token;
}
}
}
3.naver.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-naver-v2';
import { AuthService } from '../auth.service';
@Injectable()
export class NaverStrategy extends PassportStrategy(Strategy, 'naver') {
constructor(private readonly authService: AuthService) {
super({
clientID: process.env.NAVER_ID,
clientSecret: process.env.NAVER_SECRET,
callbackURL: '/auth/naver/callback',
});
}
async validate(
accessToken: string,
refreshToken: string,
profile: any,
done: any,
): Promise<any> {
// profile에서 정보 추출
const email = profile.email;
const nickname = profile.name;
const provider = profile.provider;
// user 정보 확인
const exUser = await this.authService.validateUser(email);
if (exUser) {
const token = await this.authService.getToken({ userId: exUser.userId });
return token;
}
if (exUser === null) {
const newUser = await this.authService.create({
email,
nickname,
provider,
});
const token = await this.authService.getToken({ userId: newUser.userId });
return token;
}
}
}
==> strategy를 통해 플랫폼에서 제공해주는 정보를 받아올 수 있다.
- auth
1. auth.module.ts
import { forwardRef, Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { PassportModule } from '@nestjs/passport';
import { KakaoStrategy } from 'src/auth/strategy/kakao.strategy';
import { NaverStrategy } from 'src/auth/strategy/naver.strategy';
import { GoogleStrategy } from 'src/auth/strategy/google.strategy';
import { UsersModule } from 'src/users/users.module';
@Module({
imports: [
forwardRef(() => UsersModule),
PassportModule.register({ defaultStrategy: 'jwt' }),
],
providers: [AuthService, KakaoStrategy, NaverStrategy, GoogleStrategy],
exports: [AuthService, PassportModule],
})
export class AuthModule {}
- users.controller.ts
import { Controller, Res, Req, Get, UseGuards } from '@nestjs/common';
import { Response } from 'express';
import { AuthService } from 'src/auth/auth.service';
import { GoogleAuthGuard } from 'src/auth/guard/google-auth.guard';
import { KakaoAuthGuard } from 'src/auth/guard/kakao-auth.guard';
import { NaverAuthGuard } from 'src/auth/guard/naver-auth.guard';
@Controller()
export class UsersController {
constructor(private readonly authService: AuthService) {}
/* 카카오 로그인 서비스*/
@UseGuards(KakaoAuthGuard)
@Get('auth/kakao')
async kakaoLogin() {
return;
}
@UseGuards(KakaoAuthGuard)
@Get('auth/kakao/callback')
async kakaoCallback(@Req() req: any, @Res() res: Response) {
// res.cookie('authorization', req.user);
// res.setHeader('Set-Cookie', req.user);
res.redirect('http://localhost:3000');
}
/*네이버 로그인 서비스*/
@UseGuards(NaverAuthGuard)
@Get('auth/naver')
async naverLogin() {
return;
}
@UseGuards(NaverAuthGuard)
@Get('auth/naver/callback')
async naverCallback(@Req() req: any, @Res() res: Response) {
res.redirect('http://localhost:3000');
}
/*구글 로그인 서비스*/
@UseGuards(GoogleAuthGuard)
@Get('auth/google')
async googleLogin() {
return;
}
@UseGuards(GoogleAuthGuard)
@Get('auth/google/callback')
async googleCallback(@Req() req: any, @Res() res: Response) {
res.redirect('http://localhost:3000');
}
}
==> 현재 위에 있는 코드들은 필수적으로 필요한 부분이다. 나머지는 원하는 방식으로 구현하면 된다. 필자는 repository를 이용하여 user 정보를 저장하는 것으로 구현했다.
'JavaScript Dev. > Nest.js' 카테고리의 다른 글
Nest.js - Module (0) | 2024.02.28 |
---|---|
Nest.js 설치부터 기본 개념까지 (1) | 2024.02.06 |
Nest.js와 OOP(객체지향 프로그래밍) (0) | 2024.01.14 |
Nest.js를 이용한 refresh token 구현하기 (0) | 2023.11.16 |
Nest.js (0) | 2023.08.18 |