[HELP!!!] URL 단축기 만들기 - 14-1. 디스코드 로그인 구현하기
H..E..L....P........
안될 것 같다면 인증쪽을 직접 구현해보거나 express로 돌아갈게요...

이 글은 위 글 기반으로 만들어졌어요!
그래서 인증은 passport 기반으로 처리될 예정이에요!(디스코드, JWT 사용)
passport 설치하기
yarn add @nestjs/passport passport passport-discord
passport
패키지와 passport-discord
패키지를 설치해줬어요.
passport
는 인증 기능?을 담당하고 passport-discord
는 passport에서 디스코드 로그인을 할수 있게 만들어주는 역할을 해요.
인증 모듈 만들기
nest g mo auth
이러면 auth.module.ts
가 생성될거에요. 이제 디스코드 로그인으로 넘어가 볼게요.
그 전에... 설정 파일을 좀 건드려볼게요.
설정 파일 수정하기
{
"database": {
"host": "localhost"
},
"auth": {
"discord": {
"clientId": "",
"clientSecret": "",
"redirectUri": ""
}
}
}
config.example.json을 수정해 주세요.
discord
부분은 config.json
으로 옮겨서 값을 채워넣어 주세요.
설정 타입도 수정해 줄게요.
export type Config = {
database: EdgeDB.ConnectOptions
auth: AuthConfig
}
export type AuthConfig = {
discord: {
clientId: string
clientSecret: string
redirectUri: string
}
}
인증 서비스 만들기
코드를 생성해주세요.
nest g s auth
그리고 유저 모듈을 import 해주세요.
// ...
imports: [UsersModule],
// ...
그리고 유저 모듈에서 users service를 export 해주세요.
// ...
exports: [UsersService],
// ...
이렇게 하면 auth 모듈에서 users 모듈을 사용할 수 있게 돼요. 그리고 빼먹은게 하나 있어서 유저 모듈을 수정해줄게요. changeUsername
메서드를 만들어 줬어요.
그 전에 쿼리를 하나 추가해 줄게요. 이름은 changeUsername.edgeql
이에요.
select (
update User filter .userId = <str>$id set {
username := <str>$username
}
) {
userId,
username,
admin
}
/**
* Changes username for a user
* @param id the id of user to change username
* @param username the username to change for the user
*/
async changeUsername(id: string, username: string): Promise<User> {
await this.findUserById(id) // check if user exists
const user = await changeUsername(this.db, { id, username })
return {
id: user.userId,
admin: user.admin,
username: user.username,
}
}
테스트 코드도 추가해 줄게요.
it('change username', async () => {
await expect(service.changeUsername(userId, 'Test User!')).resolves.toEqual(
{
id: '-1',
username: 'Test User!',
admin: false,
},
)
})
이제 인증 서비스 코드를 써줄게요.
일단 코드를 이렇게 써줬는데요.
import { Injectable } from '@nestjs/common'
import { UsersService } from '../users/users.service'
import { User } from '../users/types'
@Injectable()
export class AuthService {
constructor(private usersService: UsersService) {}
async findOrCreateUser(id: string, username: string): Promise<User> {
try {
let user = await this.usersService.findUserById(id)
if (user.username != username) {
user = await this.usersService.changeUsername(id, username)
}
return user
} catch {
return await this.usersService.createUser(id, username)
}
}
}
테스트 코드도 써볼게요.
import { Test, TestingModule } from '@nestjs/testing'
import { AuthService } from './auth.service'
import { UsersModule } from '../users/users.module'
import { edgedbClient } from '../database/client'
describe('AuthService', () => {
let service: AuthService
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [UsersModule],
providers: [AuthService],
}).compile()
service = module.get<AuthService>(AuthService)
})
afterAll(async () => {
await edgedbClient.execute(`delete User filter .userId = "-2";`)
})
it('should be defined', () => {
expect(service).toBeDefined()
})
it('should create a user', async () => {
await expect(
service.findOrCreateUser('-2', 'Test User 2'),
).resolves.toEqual({
id: '-2',
username: 'Test User 2',
admin: false,
})
})
it('should edit a user', async () => {
await expect(
service.findOrCreateUser('-2', 'Test User 2@'),
).resolves.toEqual({
id: '-2',
username: 'Test User 2@',
admin: false,
})
})
})
유저 서비스 작성이 끝났어요. 아마도요.
디스코드 strategy 만들기
아까 설치한 passport-discord
패키지를 이용해 디스코드 로그인을 위한 strategy를 만들어 볼거에요.
auth
폴더 아래에 discord.strategy.ts
를 만들어 주세요.
import { PassportStrategy } from '@nestjs/passport'
import { Strategy } from 'passport-discord'
import { config } from '../utils/config'
import { AuthService } from './auth.service'
import { Injectable, UnauthorizedException } from '@nestjs/common'
@Injectable()
export class DiscordStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({
clientID: config.auth.discord.clientId,
clientSecret: config.auth.discord.clientSecret,
callbackURL: config.auth.discord.redirectUri,
scope: 'identify',
})
}
async validate(
accessToken: string,
refreshToken: string,
profile: { id: string; username: string },
) {
try {
const user = await this.authService.findOrCreateUser(
profile.id,
profile.username,
)
return user
} catch {
throw new UnauthorizedException()
}
}
}
이건 뭐라 설명을 못하겠어요...
인증 컨트롤러 만들기
항상 그랬듯이 코드 생성부터 할게요.
nest g co auth
일단 작동하는지 확인하려고 로그만 찍어봤어요.
import { Controller, Request, Get, UseGuards } from '@nestjs/common'
import { AuthGuard } from '@nestjs/passport'
import { FastifyRequest } from 'fastify'
@Controller('auth')
export class AuthController {
@Get('/login')
@UseGuards(AuthGuard('discord'))
async login(@Request() req: FastifyRequest) {
console.log(req.context)
}
}
Fastify 지원을 위한 발악
열심히 만들다가...돌려보니까...작동은 안하더라고요..?
그래서 일단 열심히 삽질을 했어요
관련 패키지를 설치해 줄게요
yarn add @fastify/session @fastify/cookie
그리고 package.json을 수정해 주세요
"passport": "npm:@fastify/passport@2.2.0"
패키지 다시 설치..
yarn
main.ts를 수정...
import { NestFactory } from '@nestjs/core'
import { ValidationPipe } from '@nestjs/common'
import { AppModule } from './app.module'
import {
NestFastifyApplication,
FastifyAdapter,
} from '@nestjs/platform-fastify'
import passport from 'passport'
import fastifySession from '@fastify/session'
import fastifyCookie from '@fastify/cookie'
import { config } from './utils/config'
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
)
await app.register(fastifyCookie)
await app.register(fastifySession, {
secret: config.auth.secret,
})
await app.register(passport.initialize())
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
}),
)
await app.listen(3000)
}
bootstrap()
이렇게 했더니
Error: @fastify/session tried to access @fastify/cookie, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.
이건 일단 무시(?) 할수있는 방법으로 진행해줄게요.
.yarnrc.yml에 아래 코드를 추가해 주세요.
pnpMode: loose
그러고 다시 설치...
yarn
그러고 실행하면...아마도 작동을...할..걸요?
실행을...해보니....

이러면서 작동을 안하더라고요...
그렇게 저는 해결을 못했습니다......
누군가 도와주기를 바라면서 저는 도망가도록 할...게요...네....ㅋㅋㅋㅋ....