URL 단축기 만들기 - 14.2 로그인 직접 구현하기

2023년 1월 24일

아무래도 fastify + passport + nestjs 조합은 힘들거같아 직접 구현하기로 했어요.

그럼 전에 설치했던 모듈들 싹 지워줄게요.

yarn remove passport passport-discord @nestjs/passport @fastify/session @fastify/cookie

types 패키지는 저기서 알아서 지워주니까 딱히 따로 지울 필요는 없어요.

그다음 passport module과 strategy도 지워줄게요.

discord.strategy.ts를 지우고 PassportModule 임포트도 제거해줬어요.

그리고 메인파일도 원래대로 돌려뒀어요.

import { NestFactory } from '@nestjs/core'
import { ValidationPipe } from '@nestjs/common'
import { AppModule } from './app.module'
import {
  NestFastifyApplication,
  FastifyAdapter,
} from '@nestjs/platform-fastify'

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
  )

  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true,
    }),
  )

  await app.listen(3000, '0.0.0.0')
}
bootstrap()

일단 리다이렉트를 시켜볼게요.

@Get('/login')
async login(@Response() res: FastifyReply, @Query('code') code: string) {
  if (!code) {
    res.redirect(
      302,
      `https://discord.com/api/oauth2/authorize?${new URLSearchParams({
        client_id: config.auth.discord.clientId,
        scope: 'identify',
        redirect_uri: config.auth.discord.redirectUri,
        response_type: 'code',
      })}`,
    )
    return
  }
  console.log(code)
}

일단 리다이렉트는 성공했어요. 이제 code를 이용해서 유저정보를 불러와볼게요.

code로부터 유저 정보 가져오기

일단 이 과정을 위해서는 웹 요청을 보내야해요. axios를 설치해 줄게요.

yarn add axios

그리고 디스코드 api를 사용하기 때문에 관련 타입도 설치해 줄게요.

yarn add discord-api-types

디스코드 api용 axios 인스턴스를 만들어 줬어요.

import axios from 'axios'

const discordApi = axios.create({
  baseURL: 'https://discord.com/api/v10',
})
auth.controller.ts

이제 code에서 토큰을 가져와볼게요.

const { data: tokens } =
  await discordApi.post<RESTPostOAuth2AccessTokenResult>(
    Routes.oauth2TokenExchange(),
    new URLSearchParams({
      client_id: config.auth.discord.clientId,
      client_secret: config.auth.discord.clientSecret,
      redirect_uri: config.auth.discord.redirectUri,
      grant_type: 'authorization_code',
      code,
    }),
    {
      headers: {
        'content-type': 'application/x-www-form-urlencoded',
      },
    },
  )

const accessToken = tokens.access_token

이 코드는 디스코드 api를 이용해서 oauth2 code로 액세스 토큰을 받아와요. 이제 이 액세스 토큰을 이용해서 유저정보를 불러올 수 있어요.

const { data: discordUser } = await discordApi.get<APIUser>(Routes.user(), {
  headers: {
    authorization: `Bearer ${accessToken}`,
  },
})

이렇게 토큰을 이용해 유저를 가져왔어요.

이제 이 정보에 맞는 계정을 생성하거나 가져와서 토큰으로 변환해줄 거에요.

const user = await this.authService.findOrCreateUser(discordUser.id, discordUser.username)

먼저 유저 가입 처리?를 먼저 해줬어요.

아직 jwt 모듈 세팅을 안해둬서 이제 해볼게요.

JWT 세팅

yarn add @nestjs/jwt
JwtModule.register({
  secret: config.auth.secret,
  signOptions: {
    expiresIn: '7d',
  },
}),

그리고 AuthService도 export 해주세요.

그 다음 AuthService에 메서드를 하나 추가해 줄게요.

먼저 constructor에 jwt service를 추가해 줄게요.

constructor(
  private usersService: UsersService,
  private jwtService: JwtService,
) {}

그 다음 메서드를 추가해 줬어요.

async createToken(user: User): Promise<string> {
  return this.jwtService.signAsync({
    id: user.id,
  })
}

일단 서비스 세팅은 끝났...을 거에요. 아마도...

토큰 응답 보내기

이제 토큰을 생성해 줄거에요.

const token = await this.authService.createToken(user)

이제 토큰을 만들었으니 응답을 보내볼 차례에요. 리다이렉트를 시켜줄게요.

res.redirect(302, '/#/auth/callback?token=' + token)

이제 이러면 리다이렉트가...되겠죠?

다음 글에서 이 토큰을 사용해서 요청을 처리하는 시스템을 구축해 볼거에요.

다음이 언제일지는 모르겠지만...

GitHub - paringparing/url-shortener: something
something. Contribute to paringparing/url-shortener development by creating an account on GitHub.

파링

바보