[Service]
// 사용자 로그인 함수
interface SignInProps {
email: string;
password: string;
}
export const signIn = async (signInProps: SignInProps): Promise<{ token: string, user: UserEntity }> => {
try {
const findUser = await userRepository.findOne({
where: { email: signInProps.email }
});
if (!findUser) {
throw new Error('User not found');
}
// compare password
if (!comparePassword({password: signInProps.password, hashedPassword: findUser.password})) {
throw new Error('Password is incorrect');
}
// create Token
const token = generateToken({userId: findUser.id, role: findUser.role})
return { token, user: findUser };
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
}
throw new Error('Internal Server Error');
}
}
- 사용자 로그인 시에는 이메일과 비밀번호를 입력 받음
- 1. DB에서 일치하는 email 정보가 있는 지 확인하고 없다면 사용자를 찾을 수 없다는 문구를 보내줌
- 2. 찾은 사용자가 있다면 DB에서 찾은 사용자 비밀번호와, 사용자가 입력한 비밀번호가 일치하는 지 확인
- 이때 DB에서 찾은 사용자 비밀번호는 암호화 되어 있기 때문에 Compare 함수로 확인 해줘야 함
[bcrypt]
import bcrypt from 'bcryptjs';
const SALT_ROUNDS = Number(process.env.SALT_ROUNDS);
// 비밀번호 암호화
export const hashPassword = ({password}:{password: string}) => {
const salt = bcrypt.genSaltSync(SALT_ROUNDS); // salt 생성
return bcrypt.hashSync(password, salt); // 암호화된 비밀번호 반환
};
// 비밀번호 비교
interface ComparePasswordProps {
password: string;
hashedPassword: string;
}
export const comparePassword = ({password, hashedPassword}: ComparePasswordProps): boolean => {
return bcrypt.compareSync(password, hashedPassword); // 비밀번호 비교
};
- 사용자가 입력한 비밀번호가 첫 번째 매개변수이며, DB에 저장 되어 있었던 비밀번호는 두 번째 매개변수로 받음
- 비밀번호를 비교하고 두 비밀번호가 동일하면 JWT 토큰을 발급받음
- 이후에 Service에서는 JWT토큰과 사용자 정보 객체를 반환해줌
[jwtConfig]
import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.JWT_SECRET
// JWT 생성 함수
interface GenerateTokenProps {
userId: number;
role: number;
}
export const generateToken = (generateProps: GenerateTokenProps) => {
if (!JWT_SECRET) {
throw new Error('cannot find JWT_SECRET');
}
const payload = { userId: generateProps.userId, role: generateProps.role }; // payload는 사용자 고유 정보
const options = { expiresIn: '1h' }; // 1시간 유효한 토큰
return jwt.sign(payload, JWT_SECRET, options);
};
- 토큰의 유효시간은 1시간 / 1시간 이후에는 토큰이 만료 되어 사용자 인증 시에는 사용할 수 없는 방식으로 구현
- 토큰을 만들 때의 서명 값으면 사용자 ID, 사용자 권한 (Role)을 사용
[Controller]
// @route post /users/login
// @body { email, password }
export const signIn = async (req: Request, res: Response) => {
try {
const { email, password } = req.body;
validSignInInputService({email, password});
const { token, user } = await signInService({email, password});
responseSuccess(res, { token, user }, 'User logged in successfully', 200);
return
} catch (error) {
if (error instanceof Error) {
responseError(res, error.message, 'Failed to login', 400);
return
}
responseError(res, 'Internal Server Error', 'Failed to login', 500);
return
}
}
이후 반환 받은 토큰과 사용자 객체를 반환 해주며 기능 구현 완료
결과
'Nodejs' 카테고리의 다른 글
NodeJS typeORM 단방향 참조 (1) | 2024.12.22 |
---|---|
NodeJS 로그아웃 기능 구현 (1) | 2024.12.20 |
NodeJS 회원가입 기능 구현 (1) | 2024.12.20 |
Postgresql TypeORM으로 마이그레이션 하기 (0) | 2024.12.19 |
Nodejs PostgreSQL 연동 (1) | 2024.12.18 |