๋น๋ฐ๋ฒํธ ์ฌ์ค์ ๊ธฐ๋ฅ
๊ฐ์ ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ
- ์ด๊ธฐ ๋ก๊ทธ์ธ ์ ๊ฐ์ ๋ณ๊ฒฝ:
needsPasswordReset ํ๋๊ทธ๋ก ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ์๊ตฌ
- ๋ชจ๋ฌ ๊ธฐ๋ฐ ๋ณ๊ฒฝ: ๋ก๊ทธ์ธ ํ ์ฆ์ ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ๋ชจ๋ฌ ํ์
- ์ทจ์ ์ ๋ก๊ทธ์์: ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ์ ๊ฑฐ๋ถํ๋ฉด ์๋ ๋ก๊ทธ์์ ์ฒ๋ฆฌ
- ๋ค๋ฅธ ๊ธฐ๋ฅ ์ ๊ทผ ์ ํ: ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ์๋ฃ ์ ๊น์ง ๋ค๋ฅธ ๊ธฐ๋ฅ ์ฌ์ฉ ๋ถ๊ฐ
// ๋ก๊ทธ์ธ ์ ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ํ์ ์ฌ๋ถ ํ์ธ
public LoginResult login(LoginRequestDto loginDto) {
User user = userRepository.findByEmail(loginDto.getEmail())
.orElseThrow(() -> new UserNotFoundException("ํด๋น ์ด๋ฉ์ผ๋ก ๋ฑ๋ก๋ ์ฌ์ฉ์๊ฐ ์์ต๋๋ค."));
if (!passwordEncoder.matches(loginDto.getPassword(), user.getPassword())) {
throw new InvalidCredentialsException("๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.");
}
user.updateLastLogin();
userRepository.save(user);
Role userRole = getUserRole(user);
String accessToken = jwtTokenService.createAccessToken(user.getId(), userRole, null);
String refreshToken = jwtTokenService.createRefreshToken(user.getId());
saveOrUpdateRefreshToken(user.getId(), refreshToken);
return LoginResult.builder()
.refreshToken(refreshToken)
.accessToken(accessToken)
.expiresIn(jwtTokenService.getAccessTokenTTL())
.userId(user.getId())
.email(user.getEmail())
.name(user.getName())
.role(userRole.name())
.needsPasswordReset(user.getNeedsPasswordReset()) // ๋น๋ฐ๋ฒํธ ์ฌ์ค์ ํ์ ์ฌ๋ถ
.build();
}
๋น๋ฐ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ
- ๋ณต์ก๋ ์๊ตฌ์ฌํญ: 8์ ์ด์, ์๋ฌธ ๋์๋ฌธ์, ์ซ์, ํน์๋ฌธ์ ํฌํจ
- ์ค์๊ฐ ๊ฒ์ฆ: ์
๋ ฅ ์ค ์ค์๊ฐ์ผ๋ก ๋น๋ฐ๋ฒํธ ๊ท์น ํ์ธ
- ์๊ฐ์ ํผ๋๋ฐฑ: ๊ฐ ๊ท์น๋ณ ์ฒดํฌ ํ์๋ก ์ฌ์ฉ์ ๊ฐ์ด๋
- ์๋ฒ ์ฌ์ด๋ ๊ฒ์ฆ: ํด๋ผ์ด์ธํธ ๊ฒ์ฆ๊ณผ ๋ณ๋๋ก ์๋ฒ์์๋ ๊ฒ์ฆ
// ๋น๋ฐ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ
@ValidPassword
@Size(min = 8, max = 20, message = "๋น๋ฐ๋ฒํธ๋ 8์ ์ด์ 20์ ์ดํ์ฌ์ผ ํฉ๋๋ค.")
private String newPassword;
// ์ปค์คํ
๋น๋ฐ๋ฒํธ ๊ฒ์ฆ๊ธฐ
public class PasswordValidator implements ConstraintValidator<ValidPassword, String> {
@Override
public boolean isValid(String password, ConstraintValidatorContext context) {
if (password == null || password.isEmpty()) {
return false;
}
// ์ต์ 8์ ์ด์
if (password.length() < 8) {
return false;
}
// ์๋ฌธ ๋๋ฌธ์ ํฌํจ
if (!password.matches(".*[A-Z].*")) {
return false;
}
// ์๋ฌธ ์๋ฌธ์ ํฌํจ
if (!password.matches(".*[a-z].*")) {
return false;
}
// ์ซ์ ํฌํจ
if (!password.matches(".*[0-9].*")) {
return false;
}
// ํน์๋ฌธ์ ํฌํจ
if (!password.matches(".*[!@#$%^&*()_+\\\\\\\\-=\\\\\\\\[\\\\\\\\]{}|;':\\\\",./<>?].*")) {
return false;
}
return true;
}
}
๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ์ฒ๋ฆฌ
- ํ์ฌ ๋น๋ฐ๋ฒํธ ํ์ธ: ๊ธฐ์กด ๋น๋ฐ๋ฒํธ ์ผ์น ์ฌ๋ถ ๊ฒ์ฆ
- BCrypt ํด์ฑ: ์ ๋น๋ฐ๋ฒํธ๋ฅผ ์์ ํ๊ฒ ํด์ํํ์ฌ ์ ์ฅ
- ์ฌ์ค์ ํ๋๊ทธ ํด์ : ๋ณ๊ฒฝ ์๋ฃ ์
needsPasswordReset์ false๋ก ์ค์
- ํธ๋์ญ์
๋ณด์ฅ: ๋ฐ์ดํฐ ์ผ๊ด์ฑ์ ์ํ ํธ๋์ญ์
์ฒ๋ฆฌ
// ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ์ฒ๋ฆฌ
public void changePassword(Long userId, PasswordChangeRequestDto passwordChangeDto) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("ํด๋น ์ฌ์ฉ์๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค."));
// ํ์ฌ ๋น๋ฐ๋ฒํธ ํ์ธ
if (!passwordEncoder.matches(passwordChangeDto.getCurrentPassword(), user.getPassword())) {
throw new InvalidCredentialsException("ํ์ฌ ๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.");
}
// ์ ๋น๋ฐ๋ฒํธ๋ก ์
๋ฐ์ดํธ (ํด์ํ ํฌํจ)
user.updatePassword(passwordEncoder.encode(passwordChangeDto.getNewPassword()));
userRepository.save(user);
log.info("[Auth Service] ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ์๋ฃ - userId: {}", userId);
}
// User ์ํฐํฐ์ ๋น๋ฐ๋ฒํธ ์
๋ฐ์ดํธ ๋ฉ์๋
public void updatePassword(String newHashedPassword) {
this.password = newHashedPassword;
this.needsPasswordReset = false; // ์ฌ์ค์ ํ๋๊ทธ ํด์
}
ํ๋ก ํธ์๋ ์ฌ์ฉ์ ๊ฒฝํ