๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ๊ธฐ๋Šฅ

๊ฐ•์ œ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ

// ๋กœ๊ทธ์ธ ์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ํ•„์š” ์—ฌ๋ถ€ ํ™•์ธ
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();
}

๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

// ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
@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;
    }
}

๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ์ฒ˜๋ฆฌ

// ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ์ฒ˜๋ฆฌ
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; // ์žฌ์„ค์ • ํ”Œ๋ž˜๊ทธ ํ•ด์ œ
}

ํ”„๋ก ํŠธ์—”๋“œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜