Nodejs

NodeJS 로그인 기능 구현

_HelloWorld_ 2024. 12. 20. 12:21

[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