join을 통해 회원가입을 했다면, 패스워드는 암호화 된 후 db에 저장되어야 한다. 이후 login을 할때 service에서는 login password와, db에 저장된 암호를 decode해 일치하는지를 검사한다.
로그인 시 password가 성공적으로 일치한다면, spring server에서는 유저에게 유효기간이 있는 token을 발급한다. 이때 토큰을 생성하기 위해 필요한 것이 secretKey이다.
@Value("${jwt.secret-key}")
jwt:
secret-key: heada-health.headal_health_2023_secret_key
# 30 days
token.expired-time-ms: 25920000
secret-key는 256byte이상의 문자열로 지정하면 된다.
build.gradle에 jwt, security관련 dependency를 추가해준다.
implementation("org.springframework.boot:spring-boot-starter-security")
// implementation("org.springframework.security:spring-security-test")
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
UserController.class에 다음과 같이 작성한다.
Login에 사용되는 parameter와 return값은 이후 변경점이 생길 수 도 있음을 고려하여 따로 request, response class를 작성해주었다.
@PostMapping("/login")
public UserLoginResponse login(@RequestBody UserLoginRequest request){
String token = userService.login(request.getName(), request.getPassword());
return new UserLoginResponse(token);
}
package com.haedal.controller.request;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class UserLoginRequest {
private String username;
private String password;
}
package com.haedal.controller.response;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class UserLoginResponse {
private String token;
}
User create API의 경우에도 마찬가지로 User정보를 UserService로 보내는 API를 작성한다.
@PostMapping("/user")
public UserDto create(@RequestBody User user){
//TODO : USER DTO-> USER Request
User pullUser = userService.sign(user);
return pullUser;
}
서비스에는 password를 암호화하거나, 암호화된 password와 사용자가 입력한 password가 일치하는 로직을 구현하기 위해 BCryptPasswordEncoder 가 사용된다.
1. BCryptPasswordEncoder란?
스프링 시큐리티(Spring Seurity) 프레임워크에서 제공하는 클래스 중 하나로 비밀번호를 암호화하는 데 사용할 수 있는 메서드를 가진 클래스입니다.
스프링 시큐리티(Spring Security)란 자바 서버 개발을 위해 필요로 한 인증, 권한 부여 및 기타 보안 기능을 제공하는 프레임워크(클래스와 인터페이스 모임)입니다.
- BCryptPasswordEncoder는 BCrypt 해싱 함수(BCrypt hashing function)를 사용해서 비밀번호를 인코딩해주는 메서드와 사용자의 의해 제출된 비밀번호와 저장소에 저장되어 있는 비밀번호의 일치 여부를 확인해주는 메서드를 제공합니다.
- PasswordEncoder 인터페이스를 구현한 클래스입니다.
- 생성자의 인자 값(verstion, strength, SecureRandom instance)을 통해서 해시의 강도를 조절할 수 있습니다.
(출처 : https://kimvampa.tistory.com/129)
- encode(java.lang.CharSequence rawPassword)
패스워드를 암호화- matchers(java.lang.CharSequence rawPassword, java.lang.String encodePassword)
인코딩 되지 않은 패스워드와 인코딩 된 패스워드의 일치 여부를 확인
@Value에 적은 값은 우리가 application.yaml에 작성한 값으로, spring에서 매칭해준다.
암호화할때 해시 키를 위해 필요한 값이다.
(빨간 줄을 없애기 위해 service 위에 @RequestArgsConstructor)를 추가해주어야 한다.
이렇게 하면
encoder의 type을 찾을 수 없다는 빨간줄이 뜨는데, config 폴더 하나를 만들고 다음과 같이
encoderPassword라는 생성자 Bean을 생성해주면 된다.