현재 비번 검증 후 BCrypt 교체. 소셜 계정/동일 비번 거부. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ package com.sb.web.auth.controller;
|
||||
import com.sb.web.auth.dto.LoginRequest;
|
||||
import com.sb.web.auth.dto.LoginResponse;
|
||||
import com.sb.web.auth.dto.MemberResponse;
|
||||
import com.sb.web.auth.dto.PasswordChangeRequest;
|
||||
import com.sb.web.auth.dto.SessionUser;
|
||||
import com.sb.web.auth.dto.SignupRequest;
|
||||
import com.sb.web.auth.service.AuthService;
|
||||
@@ -48,4 +49,12 @@ public class AuthController {
|
||||
public SessionUser me(@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) {
|
||||
return current;
|
||||
}
|
||||
|
||||
@PutMapping("/password")
|
||||
public ResponseEntity<Void> changePassword(
|
||||
@Valid @RequestBody PasswordChangeRequest req,
|
||||
@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) {
|
||||
authService.changePassword(current.getId(), req);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.sb.web.auth.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 비밀번호 변경 요청 (로그인 사용자 본인).
|
||||
*/
|
||||
@Data
|
||||
public class PasswordChangeRequest {
|
||||
|
||||
@NotBlank(message = "현재 비밀번호를 입력하세요.")
|
||||
private String currentPassword;
|
||||
|
||||
@NotBlank(message = "새 비밀번호를 입력하세요.")
|
||||
@Size(min = 8, max = 64, message = "비밀번호는 8~64자여야 합니다.")
|
||||
private String newPassword;
|
||||
}
|
||||
@@ -20,4 +20,6 @@ public interface MemberMapper {
|
||||
int countByLoginId(@Param("loginId") String loginId);
|
||||
|
||||
int insert(Member member);
|
||||
|
||||
int updatePassword(@Param("id") Long id, @Param("password") String password);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.sb.web.auth.domain.Member;
|
||||
import com.sb.web.auth.dto.LoginRequest;
|
||||
import com.sb.web.auth.dto.LoginResponse;
|
||||
import com.sb.web.auth.dto.MemberResponse;
|
||||
import com.sb.web.auth.dto.PasswordChangeRequest;
|
||||
import com.sb.web.auth.dto.SessionUser;
|
||||
import com.sb.web.auth.dto.SignupRequest;
|
||||
import com.sb.web.common.exception.ApiException;
|
||||
@@ -99,4 +100,26 @@ public class AuthService {
|
||||
redisTemplate.delete(SESSION_PREFIX + token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 비밀번호 변경 (본인). 현재 비밀번호 검증 후 새 비밀번호로 교체.
|
||||
*/
|
||||
@Transactional
|
||||
public void changePassword(Long memberId, PasswordChangeRequest req) {
|
||||
Member member = memberMapper.findById(memberId);
|
||||
if (member == null) {
|
||||
throw new ApiException(HttpStatus.NOT_FOUND, "회원을 찾을 수 없습니다.");
|
||||
}
|
||||
if (!"LOCAL".equals(member.getProvider()) || member.getPassword() == null) {
|
||||
throw new ApiException(HttpStatus.BAD_REQUEST, "소셜 로그인 계정은 비밀번호를 변경할 수 없습니다.");
|
||||
}
|
||||
if (!passwordEncoder.matches(req.getCurrentPassword(), member.getPassword())) {
|
||||
throw new ApiException(HttpStatus.BAD_REQUEST, "현재 비밀번호가 올바르지 않습니다.");
|
||||
}
|
||||
if (passwordEncoder.matches(req.getNewPassword(), member.getPassword())) {
|
||||
throw new ApiException(HttpStatus.BAD_REQUEST, "새 비밀번호가 기존 비밀번호와 동일합니다.");
|
||||
}
|
||||
memberMapper.updatePassword(memberId, passwordEncoder.encode(req.getNewPassword()));
|
||||
log.info("[password] changed for {}", member.getLoginId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ public class WebConfig implements WebMvcConfigurer {
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 인증: 로그인 필요한 경로 (관리자 경로 포함 — SessionUser 세팅용으로 먼저 실행)
|
||||
registry.addInterceptor(authInterceptor)
|
||||
.addPathPatterns("/api/auth/me", "/api/auth/logout", "/api/board/**", "/api/admin/**", "/api/account/**");
|
||||
.addPathPatterns("/api/auth/me", "/api/auth/logout", "/api/auth/password",
|
||||
"/api/board/**", "/api/admin/**", "/api/account/**");
|
||||
// 인가: 관리자 전용 경로 (authInterceptor 다음에 실행되어 role 검사)
|
||||
registry.addInterceptor(adminInterceptor)
|
||||
.addPathPatterns("/api/admin/**");
|
||||
|
||||
Reference in New Issue
Block a user