회원가입 로직 설명
1. postRegisterEmail
메서드 (컨트롤러)
@Post('register/email')
postRegisterEmail(
@Body('email') email: string,
@Body('password') password: string,
@Body('nickname') nickname: string,
) {
return this.authService.registerWithEmail({
nickname,
email,
password,
});
}
postRegisterEmail
메서드는 회원가입 요청을 처리하는 엔드포인트입니다.
- 요청 바디에서
email
, password
, nickname
값을 받아 authService.registerWithEmail
로 전달합니다.
- 이 메서드는
AuthService
에서 회원가입 처리를 진행하도록 하는 역할을 합니다.
2. registerWithEmail
메서드 (AuthService)
async registerWithEmail(user: Pick<UsersModel, 'nickname' | 'email' | 'password'>) {
const hash = await bcrypt.hash(
user.password,// 사용자 비밀번호를 해싱합니다.HASH_ROUNDS,// 해싱 라운드를 설정하여 보안을 강화합니다.
);
const newUser = await this.usersService.createUser({
...user,// 나머지 속성은 그대로 사용password: hash,// 해시된 비밀번호를 password에 덮어씁니다.
});
return this.loginUser(newUser);// 생성된 사용자로 액세스 토큰과 리프레시 토큰 발급
}
registerWithEmail
메서드는 회원가입에 필요한 데이터를 전달받아 처리합니다.
bcrypt.hash()
메서드를 사용해 user.password
를 해싱하고, 해싱된 결과를 hash
변수에 저장합니다.
HASH_ROUNDS
는 비밀번호를 반복적으로 해싱하는 횟수로, 보안을 강화하는 역할을 합니다.
- 해싱된 비밀번호와 함께
user
데이터를 usersService.createUser
메서드로 전달하여 데이터베이스에 새 사용자를 저장합니다.
- 마지막으로, 새로 생성된 사용자 정보(
newUser
)로 loginUser
메서드를 호출하여 액세스 토큰과 리프레시 토큰을 발급합니다. 이는 회원가입 후 사용자가 별도의 로그인 과정을 거치지 않고 바로 로그인되도록 하기 위함입니다.
3. createUser
메서드 (UsersService)
async createUser(user: Pick<UsersModel, 'email' | 'nickname' | 'password'>) {
const nicknameExists = await this.usersRepository.exist({
where: {
nickname: user.nickname,// 중복 닉네임 조건
}
});
if (nicknameExists) {
throw new BadRequestException('이미 존재하는 nickname 입니다.');
// 중복 닉네임 에러 처리
}
const emailExists = await this.usersRepository.exist({
where: {
email: user.email,
// 중복 이메일 조건
}
});
if (emailExists) {
throw new BadRequestException('이미 존재하는 email 입니다.');
// 중복 이메일 에러 처리
}
const userObject = this.usersRepository.create({
nickname: user.nickname,
email: user.email,
password: user.password,// 해시된 비밀번호
});
const newUser = await this.usersRepository.save(userObject);
// 데이터베이스에 실제로 저장return newUser;// 저장된 새 사용자 반환
}
createUser
메서드는 nickname
과 email
의 중복 여부를 확인하고, 중복될 경우 각각 BadRequestException
을 발생시킵니다.
exist()
메서드는 특정 조건에 맞는 데이터가 존재하는지 boolean
값으로 확인하는 메서드입니다. 닉네임이나 이메일이 데이터베이스에 있는 경우 true
, 없으면 false
를 반환합니다.
- 중복 검사가 완료되면
this.usersRepository.create()
를 통해 새로운 사용자 엔티티 userObject
를 생성합니다. 이때, 아직 데이터베이스에는 저장되지 않은 상태입니다.
this.usersRepository.save(userObject)
를 호출하여 userObject
를 실제로 데이터베이스에 저장하며, 이 저장된 사용자 객체(newUser
)를 반환합니다.
4. loginUser
메서드 (AuthService)
loginUser(user: Pick<UsersModel, 'email' | 'id'>) {
return {
accessToken: this.signToken(user, false),
// 액세스 토큰 발급
refreshToken: this.signToken(user, true),
// 리프레시 토큰 발급
};
}
loginUser
메서드는 사용자 정보를 이용해 액세스 토큰과 리프레시 토큰을 생성해 반환합니다.
- 이 메서드는 내부적으로
signToken
메서드를 두 번 호출하여 accessToken
과 refreshToken
을 각각 생성합니다.
5. signToken
메서드 (AuthService)
signToken(user: Pick<UsersModel, 'email' | 'id'>, isRefreshToken: boolean) {
const payload = {
email: user.email,
sub: user.id,
type: isRefreshToken ? 'refresh' : 'access',
// 토큰 유형 설정
};
return this.jwtService.sign(payload, {
secret: JWT_SECRET,
// JWT 시크릿 키 사용
expiresIn: isRefreshToken ? 3600 : 300,
// 만료 시간 설정 (Refresh: 1시간, Access: 5분)
});
}
signToken
메서드는 주어진 사용자 정보로 JWT 토큰을 생성하는 로직입니다.
- 토큰에 포함할
payload
객체를 생성합니다. 여기에는 email
, sub
(사용자 ID), type
이 포함됩니다. type
은 isRefreshToken
에 따라 refresh
또는 access
로 설정됩니다.
this.jwtService.sign()
메서드를 통해 토큰을 생성하며, 이때 JWT_SECRET
키와 만료 시간을 설정합니다.
- 만료 시간(
expiresIn
)은 isRefreshToken
값에 따라 다르게 적용되며, 리프레시 토큰은 1시간(3600초), 액세스 토큰은 5분(300초)입니다.
- 생성된 토큰은
loginUser
로 반환되어 최종적으로 사용자에게 전달됩니다.