[내일배움캠프 - Nest.js 개인과제] Nest.js + TypeORM | 공연 예매 사이트 만들기 - 네이버 로그인 서버 구현하기

sooyoung choi·2023년 12월 26일
1

내일배움캠프

목록 보기
7/19
post-thumbnail

네이버 로그인 서버 구현해보기

1) 오픈 API 이용 신청하기

  • 네이버 개발자 사이트 👈클릭!

  • 애플리케이션 등록 탭에서 애플리케이션 이름을 입력하고 사용 API에 네이버 로그인 을 선택한다.

  • 제공되는 정보들을 선택한다.(이름, 이메일주소 등)

  • 로그인 오픈 API 서비스 환경 중 서비스 URL과 로그인 콜백 URL을 작성한다.
  • 서비스 URL - 도메인 환경이 준비되어있지 않은 경우는 localhost 주소 사용해도 무방하다.
  • 콜백 URL - 로그인 후 네이버로부터 정보를 받아올 콜백 URL 주소를 적어준다.


2) naver 전략 파일 작성

  • 전략 파일을 작성하면서 리프레시 토큰은 쓰지 않아서 필요없는 값인 줄 알고 빼줬다가 네이버 로그인 API 측에서 제공하는 profile을 온전히 JSON 객체 형태로 받아오지 못하고 계속 string 값으로 받아왔었다.
// src/auth/naver.strategy.ts
// naver.strategy.ts
import { Strategy } from 'passport-naver';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { UserService } from 'src/user/user.service';

@Injectable()
export class NaverStrategy extends PassportStrategy(Strategy) {
  constructor(private userService: UserService) {
    super({
      clientID: process.env.NAVER_CLIENT_ID,
      clientSecret: process.env.NAVER_CLIENT_SECRET,
      callbackURL: process.env.NAVER_CALLBACK_URL,
    });
  }

  async validate(
    accessToken: string,	// 빼먹지 말고
    refreshToken: string,	// 일단 하라는 대로 적기..ㅎ
    profile: any,
  ): Promise<any> {
    console.log(profile);
    const id = profile.id;
    const email = profile._json.email;
    const name = profile.displayName;
    const provider = profile.provider;
    const user_profile = {
      id,
      email,
      name,
      provider,
    };

    return user_profile;
  }
}


3) 가드 파일 작성

// src/auth/naver-auth.guard.ts

import { AuthGuard } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';

@Injectable()
export class NaverAuthGuard extends AuthGuard('naver') {}


4) .env 파일 작성

  • 오픈소스 API 신청 후 제공되는 애플리케이션 정보 중 클라이언트 아이디 값과 시크릿 값, 그리고 콜백 URL을 env에 넣어준다.

NAVER_CLIENT_ID=""
NAVER_CLIENT_SECRET=""
NAVER_CALLBACK_URL="http://localhost:3000/user/naver/login"


5) providers 설정해주기

// src/auth/auth.module.ts

import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';
import { UserModule } from 'src/user/user.module';
import { NaverStrategy } from './naver.strategy';
import { NaverAuthGuard } from './naver-auth.guard';

@Module({
  imports: [
    PassportModule.register({ defaultStrategy: 'jwt', session: false }),
    JwtModule.registerAsync({
      useFactory: (config: ConfigService) => ({
        secret: config.get<string>('JWT_SECRET_KEY'),
      }),
      inject: [ConfigService],
    }),
    UserModule,
  ],
  // 네이버 전략과 가드를 넣어준다.
  providers: [JwtStrategy, NaverStrategy, NaverAuthGuard],
  exports: [JwtModule, PassportModule],
})
export class AuthModule {}


6) Controller

  • 콜백 URL에 따른 컨트롤러를 작성한다.
@UseGuards(AuthGuard('naver'))
  @Get('/naver/login')
  async loginNaver(@Req() req: Request, @Res() res: Response): Promise<any> {
    try {
      return await this.userService.OAuthLogin({ req, res });
    } catch (error) {
      console.error('Error in loginNaver:', error);
      res.status(500).json({ error: 'Internal Server Error' });
    }
  }


7) Service

  • 로그인이나 회원가입 할 때 필요한 값들을 생각해서 넣어줘야한다.
  • 네이버 로그인 API는 비밀번호는 제공하지 않으므로 임의로 비밀번호 값을 넣어줘야 한다.
async OAuthLogin({ req, res }) {
  
  // 네이버 이메일로 사용자를 찾는다.
    let OAuthUser = await this.userRepository.findOne({
      where: { email: req.user.email },
    });
  
  // 네이버 사용자의 이메일 값을 변수 지정 해주었다.
  const email = req.user.email;
  
  // 비밀번호 값은 따로 받아올 수 없기 때문에 user의 아이디 값을 해시화 해서 변수 지정해주었다.
  const hashedNaverPassword = await hash(req.user.id, 10);

  // 해당 이메일 사용자가 없다면 회원가입 로직처럼 회원 생성 해준다.
  // 비밀번호는 user의 아이디 값을 해시화 해서 변수 지정한 값을 사용한다.
    if (!OAuthUser) {
      OAuthUser = await this.userRepository.save({
        email,
        name: req.user.name,
        password: hashedNaverPassword,
      });
    }
  
  // 로그인 시 access token을 넣어주기 위해 사용자의 이메일과 요청된 사용자의 ID를 페이로드로 설정한다.
    const payload = { email, sub: req.user.id };

    res.redirect('/');

    return {
      message: '로그인 성공',
      success: true,
      access_token: this.jwtService.sign(payload),
      OAuthUser,
    };
  }


데이터베이스에 아주 잘 들어갔다! 😊

0개의 댓글