한 번 추가 구현 단계도 도전을 했다. 7단계를 하려면 jwt를 해야한다.
- 7단계 : 회원가입
🔻 조건
- 유저에 비밀번호 필드를 추가합니다.
- 비밀번호는 암호화되어야 합니다.
- 암호화를 위한 PasswordEncoder를 직접 만들어 사용합니다.
- 유저 최초 생성(회원가입) 시 JWT를 발급 후 반환합니다.
일단 build.gradle에 라이브러리를 추가해야한다.
implementation 'at.favre.lib:bcrypt:0.10.2'
// JWT
compileOnly group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'
비밀번호를 암호화 할 PasswordEncoder와 jwt를 생성할 JwtUtil를 생성한다.
@Component
public class PasswordEncoder {
public String encode(String rawPassword) {
return BCrypt.withDefaults().hashToString(BCrypt.MIN_COST, rawPassword.toCharArray());
}
public boolean matches(String rawPassword, String encodedPassword) {
BCrypt.Result result = BCrypt.verifyer().verify(rawPassword.toCharArray(), encodedPassword);
return result.verified;
}
}
jwt를 생성할 createToken 메서드
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String BEARER_PREFIX = "Bearer ";
private final long TOKEN_TIME = 60 * 60 * 1000L; // 60분
@Value("${jwt.secret.key}")
private String secretKey;
private Key key;
private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
public static final Logger logger = LoggerFactory.getLogger("JWT 관련 로그");
@PostConstruct
public void init() {
byte[] bytes = Base64.getDecoder().decode(secretKey);
key = Keys.hmacShaKeyFor(bytes);
}
public String createToken(String username) {
Date date = new Date();
return BEARER_PREFIX +
Jwts.builder()
.setSubject(username)
.setExpiration(new Date(date.getTime() + TOKEN_TIME))
.setIssuedAt(date)
.signWith(key, signatureAlgorithm)
.compact();
}
jwt가 생성하면 앞에 'bearer '를 분리할 substringToken 메서드
public String substringToken(String tokenValue) {
if (StringUtils.hasText(tokenValue) && tokenValue.startsWith(BEARER_PREFIX)) {
return tokenValue.substring(7);
}
logger.error("Not Found Token");
throw new NullPointerException("Not Found Token");
}
jwt를 검증할 validateToken 메서드
public boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
return true;
} catch (SecurityException | MalformedJwtException | SignatureException e) {
logger.error("Invalid JWT signature, 유효하지 않는 JWT 서명 입니다.");
} catch (ExpiredJwtException e) {
logger.error("Expired JWT token, 만료된 JWT token 입니다.");
} catch (UnsupportedJwtException e) {
logger.error("Unsupported JWT token, 지원되지 않는 JWT 토큰 입니다.");
} catch (IllegalArgumentException e) {
logger.error("JWT claims is empty, 잘못된 JWT 토큰 입니다.");
}
return false;
}
입력 받을 user의dto와 user 엔티티를 수정한다.
비밀번호를 입력할 password 필드를 추가
@Column(name = "password", nullable = false)
private String password;
비밀번호 추가
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
}
@Getter
public class UserRequestDto {
private String username;
private String password;
private String email;
}
@Getter
public class UserResponseDto {
private Long id;
private String username;
private String email;
private String token;
private LocalDateTime createdAt;
private LocalDateTime modifiedAt;
public UserResponseDto(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.email = user.getEmail();
this.createdAt = user.getCreatedAt();
this.modifiedAt = user.getModifiedAt();
}
public UserResponseDto(User user, String token) {
this.id = user.getId();
this.username = user.getUsername();
this.email = user.getEmail();
this.token = token; // Set token
this.createdAt = user.getCreatedAt();
this.modifiedAt = user.getModifiedAt();
}
}
또한 UserService에서 일정을 생성할 때 JWT를 생성할 코드 추가
JWT 생성 코드 추가
// JWT 생성
String token = jwtUtil.createToken(user.getUsername());
이러면 유저를 생성할 때 JWT도 생성된다.