본 내용은 내일배움캠프에서 활동한 내용을 기록한 글입니다.
로컬 서버에서의 Swagger에서는 CORS 문제로 카카오 로그인이 사용되지 않음
그래서 일반 웹브라우저에서 테스트 진행
사용하는 URL은 kakao developers의 Redirect URI를 사용하면 됨
즉, 기본적인 인증 과정을 우리가 하는 게 아니라 카카오에서 진행해주기 때문에 우리는 그냥 인증된 결과에 대한 값만 처리하면 됨
아래는 PassportStrategy를 상속받아서 사용한 카카오 Strategy
import { ConflictException, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { InjectRepository } from '@nestjs/typeorm';
import { Strategy } from 'passport-kakao';
import { User } from 'src/entities/users/user.entity';
import { Repository } from 'typeorm';
// KAKAO_CALLBACK_URL를 통해서 웹브라우저에서 로그인 진행
// 반환되는 토큰 값을 가지고 다른 기능들 사용
@Injectable()
export class KakaoStrategy extends PassportStrategy(Strategy, 'kakao') {
constructor(
private readonly configService: ConfigService,
@InjectRepository(User) private readonly usersRepository: Repository<User>
) {
super({
clientID: configService.get('KAKAO_CLIENT_ID'),
clientSecret: configService.get('KAKAO_CLIENT_SECRET'),
callbackURL: configService.get('KAKAO_CALLBACK_URL'),
});
}
async validate(accessToken: string, refreshToken: string, profile: any) {
const email = profile._json.kakao_account.email;
const nickname = new Date().getTime().toString(36); // 랜덤 닉네임 생성
// 기존에 가입한 사용자인지 확인
let user = await this.usersRepository.findOne({ where: { email } });
// 없는 사용자면 데이터베이스에 사용자 정보 추가
if (!user) {
user = await this.usersRepository.save({
email,
// 빈 문자열로 설정해도 이메일로 빈 이메일로 일반 로그인 할 수 없음
// PassportStrategy에서 비밀번호로 빈 문자열을 받지 못하게 되어 있어서
password: '',
nickname,
});
}
return user;
}
}
Strategy에서 해당 사용자가 있는지 검증을 하고 간단한 회원 가입을 진행함
그리고 데이터베이스에 사용자 정보를 저장할 때 비밀번호로는 빈 문자열을 줌
빈 문자열을 줘도 일반 로그인에서 사용하는 AuthGuard(’jwt’)의 PassportStrategy에서 비밀번호로 빈 문자열을 허용하지 않음
그렇기에 일반 로그인에서 소셜 이메일과 빈 문자열 비밀번호로 로그인이 불가능함
가드로 위 카카오 Strategy를 사용하기 위해서 카카오 가드를 만들어 줌
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class KakaoAuthGuard extends AuthGuard('kakao') {}
import { Body, Controller, Get, Post, Req, Res, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { SignUpDto } from './dto/sign-up.dto';
import { SignInDto } from './dto/sign-in.dto';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { KakaoAuthGuard } from './utils/kakao.guard';
@ApiTags('인증')
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
/**
* 로그인
* @param signInDto
* @returns
*/
@UseGuards(AuthGuard('local'))
@Post('/sign-in')
async signIn(@Req() req: any, @Body() signInDto: SignInDto) {
return await this.authService.signIn(req.user);
}
/**
* 카카오 로그인
* @param req
* @returns
*/
@UseGuards(KakaoAuthGuard)
@Get('/kakao')
async kakaoSignIn(@Req() req: any, @Res() res: any) {
console.log('controller : ', req.user);
const { accessToken, refreshToken } = await this.authService.signIn(req.user);
return res.send({ accessToken, refreshToken });
}
}
내일은 버블을 이용해서 프론트엔드 구현하는 방법에 대해서 공부할 예정
오늘 남은 시간동안 이것 저것 테스트 해봤는데, 생각보다 연결하고 신경써야 할게 많았음
특히나 API 연결은 되었으나 그 API를 동작시키고 반환되는 값을 어떻게 가져와야 할지 찾는 중임
이것만 해결되면 그래도 조금은 프론트엔드와 백엔드의 값 이동이 자유로울 것 같음
오늘은 Passport Strategy를 이용한 카카오 소셜 로그인을 구현함
기존에 있던 Local Strategy를 많이 참고함
kakao developers에서 필요한 ID과 키를 받아서 .env에 저장함
매 프로젝트마다 다른 분들이 작업하던 기능인데 실제로 구현해보니 생각보다 재밌었음
그리고 동작 순서와 원리를 알면 생각보다 쉽게 구현할 수 있음