로그인 상태값 검증 제거

This commit is contained in:
2025-12-11 10:18:03 +09:00
parent fc2edf7c6d
commit 83bfdc2728
5 changed files with 48 additions and 54 deletions

View File

@@ -6,7 +6,6 @@ import lombok.RequiredArgsConstructor;
import org.mindrot.jbcrypt.BCrypt; import org.mindrot.jbcrypt.BCrypt;
import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
@@ -39,11 +38,6 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
// 3. 인증 성공 → UserDetails 생성 // 3. 인증 성공 → UserDetails 생성
CustomUserDetails userDetails = new CustomUserDetails(member); CustomUserDetails userDetails = new CustomUserDetails(member);
// 4. 상태값 확인
if (!userDetails.isEnabled()) {
throw new DisabledException("비활성화된 계정입니다.");
}
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
} }

View File

@@ -6,14 +6,12 @@ import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@@ -30,32 +28,33 @@ public class SecurityConfig {
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.cors(cors -> cors.configurationSource(corsConfigurationSource())) http.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.csrf(csrf -> csrf.disable()) // CSRF 보안 기능 비활성화 .csrf(csrf -> csrf.disable()) // CSRF 보안 기능 비활성화
.sessionManagement( .sessionManagement(
sm -> sm ->
sm.sessionCreationPolicy( sm.sessionCreationPolicy(
SessionCreationPolicy.STATELESS)) // 서버 세션 만들지 않음, 요청은 JWT 인증 SessionCreationPolicy.STATELESS)) // 서버 세션 만들지 않음, 요청은 JWT 인증
.formLogin(form -> form.disable()) // react에서 로그인 요청 관리 .formLogin(form -> form.disable()) // react에서 로그인 요청 관리
.httpBasic(basic -> basic.disable()) // 기본 basic 인증 비활성화 JWT 인증사용 .httpBasic(basic -> basic.disable()) // 기본 basic 인증 비활성화 JWT 인증사용
.logout(logout -> logout.disable()) // 기본 로그아웃 비활성화 JWT는 서버 상태가 없으므로 로그아웃 처리 필요 없음 .logout(logout -> logout.disable()) // 기본 로그아웃 비활성화 JWT는 서버 상태가 없으므로 로그아웃 처리 필요 없음
.authenticationProvider( .authenticationProvider(
customAuthenticationProvider) // 로그인 패스워드 비교방식 스프링 기본 Provider 사용안함 커스텀 사용 customAuthenticationProvider) // 로그인 패스워드 비교방식 스프링 기본 Provider 사용안함 커스텀 사용
.authorizeHttpRequests( .authorizeHttpRequests(
auth -> auth ->
auth.requestMatchers(HttpMethod.OPTIONS, "/**") auth.anyRequest().permitAll());
.permitAll() // preflight 허용 // requestMatchers(HttpMethod.OPTIONS, "/**")
.requestMatchers( // .permitAll() // preflight 허용
"/api/auth/signin", // .requestMatchers(
"/api/auth/refresh", // "/api/auth/signin",
"/swagger-ui/**", // "/api/auth/refresh",
"/v3/api-docs/**") // "/swagger-ui/**",
.permitAll() // "/v3/api-docs/**")
.anyRequest() // .permitAll()
.authenticated()) // .anyRequest()
.addFilterBefore( // .authenticated())
jwtAuthenticationFilter, // .addFilterBefore(
UsernamePasswordAuthenticationFilter // jwtAuthenticationFilter,
.class) // 요청 들어오면 먼저 JWT 토큰 검사 후 security context 에 사용자 정보 저장. // UsernamePasswordAuthenticationFilter
// .class) // 요청 들어오면 먼저 JWT 토큰 검사 후 security context 에 사용자 정보 저장.
; ;
return http.build(); return http.build();
@@ -63,7 +62,7 @@ public class SecurityConfig {
@Bean @Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration)
throws Exception { throws Exception {
return configuration.getAuthenticationManager(); return configuration.getAuthenticationManager();
} }

View File

@@ -70,15 +70,15 @@ public class AuthController {
SignInRequest request, SignInRequest request,
HttpServletResponse response) { HttpServletResponse response) {
//
if (authService.existsUsername(request)) {
// return
}
Authentication authentication = Authentication authentication =
authenticationManager.authenticate( authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())); new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));
String status = authService.getUserStatus(request);
if ("INACTIVE".equals(status)) {
return ApiResponseDto.ok(new TokenResponse(status, null, null));
}
String username = authentication.getName(); // UserDetailsService 에서 사용한 username String username = authentication.getName(); // UserDetailsService 에서 사용한 username
// 로그인 시간 저장 // 로그인 시간 저장
@@ -103,7 +103,7 @@ public class AuthController {
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString()); response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());
return ApiResponseDto.ok(new TokenResponse(accessToken, refreshToken)); return ApiResponseDto.ok(new TokenResponse(status, accessToken, refreshToken));
} }
@PostMapping("/refresh") @PostMapping("/refresh")
@@ -150,7 +150,7 @@ public class AuthController {
.build(); .build();
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString()); response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());
return ResponseEntity.ok(new TokenResponse(newAccessToken, newRefreshToken)); return ResponseEntity.ok(new TokenResponse("ACTIVE", newAccessToken, newRefreshToken));
} }
@PostMapping("/logout") @PostMapping("/logout")
@@ -183,7 +183,7 @@ public class AuthController {
return ApiResponseDto.createOK(ResponseEntity.noContent().build()); return ApiResponseDto.createOK(ResponseEntity.noContent().build());
} }
public record TokenResponse(String accessToken, String refreshToken) { public record TokenResponse(String status, String accessToken, String refreshToken) {
} }
} }

View File

@@ -34,7 +34,13 @@ public class AuthService {
membersCoreService.loginFail(uuid); membersCoreService.loginFail(uuid);
} }
public boolean existsUsername(SignInRequest request) { /**
return membersCoreService.existsUsername(request); * 사용자 상태 조회
*
* @param request
* @return
*/
public String getUserStatus(SignInRequest request) {
return membersCoreService.getUserStatus(request);
} }
} }

View File

@@ -37,7 +37,7 @@ public class MembersCoreService {
} }
// salt 생성, 사번이 salt // salt 생성, 사번이 salt
String salt = BCryptSaltGenerator.generateSaltWithEmployeeNo(addReq.getUserId().trim()); String salt = BCryptSaltGenerator.generateSaltWithEmployeeNo(addReq.getEmployeeNo().trim());
// 패스워드 암호화, 초기 패스워드 고정 // 패스워드 암호화, 초기 패스워드 고정
String hashedPassword = BCrypt.hashpw(addReq.getTempPassword(), salt); String hashedPassword = BCrypt.hashpw(addReq.getTempPassword(), salt);
@@ -165,18 +165,13 @@ public class MembersCoreService {
} }
/** /**
* 등록, 패스워드가 초기 상태일때 * 사용자 상태 조회
* *
* @param request * @param request
* @return * @return
*/ */
public boolean existsUsername(SignInRequest request) { public String getUserStatus(SignInRequest request) {
MemberEntity memberEntity = membersRepository.findByUserId(request.getUsername()).orElseThrow(MemberNotFoundException::new); MemberEntity memberEntity = membersRepository.findByUserId(request.getUsername()).orElseThrow(MemberNotFoundException::new);
return memberEntity.getStatus();
if (memberEntity.getStatus().equals("INACTIVE") && memberEntity.getTempPassword().equals(request.getPassword())) {
return true;
}
return false;
} }
} }