[ADD] TODO: REFRESH TOKEN

main
bjkim 10 months ago
parent 0d6e9e3ccc
commit a5aa215b70

@ -7,14 +7,13 @@ import io.swagger.v3.oas.annotations.Parameter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import kr.re.etri.autoflow.service.AuthService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
@ -43,11 +42,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
UserRepository userRepository;
@ -63,50 +59,18 @@ public class AuthController {
@Autowired
RefreshTokenService refreshTokenService;
@Operation(summary = "로그인", description = "사용자 인증 후 JWT 및 리프레시 토큰 쿠키를 반환합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "로그인 성공"),
@ApiResponse(responseCode = "401", description = "잘못된 사용자명 또는 비밀번호")
})
@PostMapping("/signin")
public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())
);
SecurityContextHolder.getContext().setAuthentication(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
// 기존 refresh token 제거
refreshTokenService.deleteByUserId(userDetails.getId());
// 새 JWT 및 RefreshToken 생성
ResponseCookie jwtCookie = jwtUtils.generateJwtCookie(userDetails);
RefreshToken refreshToken = refreshTokenService.createRefreshToken(userDetails.getId());
ResponseCookie jwtRefreshCookie = jwtUtils.generateRefreshJwtCookie(refreshToken.getToken());
List<String> roles = userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.toList();
UserInfoResponse userInfo = new UserInfoResponse(
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList())
);
// 응답 바디에 userInfo와 쿠키 문자열 같이 넣기
Map<String, Object> responseBody = new HashMap<>();
responseBody.put("userInfo", userInfo);
responseBody.put("jwtCookie", jwtCookie.toString());
responseBody.put("jwtRefreshCookie", jwtRefreshCookie.toString());
return ResponseEntity.ok(responseBody);
}
private final AuthService authService;
@Operation(summary = "로그인", description = "사용자 인증 후 JWT 및 리프레시 토큰 쿠키를 반환합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "로그인 성공"),
@ApiResponse(responseCode = "401", description = "잘못된 사용자명 또는 비밀번호")
})
@PostMapping("/signin")
public ResponseEntity<?> signIn(@Valid @RequestBody LoginRequest request) {
Map<String, Object> response = authService.authenticate(request);
return ResponseEntity.ok(response);
}
@Operation(summary = "회원가입", description = "새로운 사용자를 등록합니다.")
@ApiResponses({

@ -83,38 +83,38 @@ public class WebSecurityConfig { // extends WebSecurityConfigurerAdapter {
// http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
// }
// @Bean
// public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// http.csrf(AbstractHttpConfigurer::disable)
// .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
// .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// .authorizeHttpRequests(auth ->
// auth.requestMatchers("/api/auth/**").permitAll()
// .requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
// .requestMatchers("/api/test/**").permitAll()
// .anyRequest().authenticated()
// );
//
// http.authenticationProvider(authenticationProvider());
//
// http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//
// return http.build();
// }
// 임시 설정
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth ->
auth.anyRequest().permitAll() // 모든 요청 허용
);
.exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth ->
auth.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
.requestMatchers("/api/test/**").permitAll()
.anyRequest().authenticated()
);
http.authenticationProvider(authenticationProvider());
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
// 임시 설정
// @Bean
// public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// http.csrf(AbstractHttpConfigurer::disable)
// .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
// .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// .authorizeHttpRequests(auth ->
// auth.anyRequest().permitAll() // 모든 요청 허용
// );
//
// http.authenticationProvider(authenticationProvider());
// http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//
// return http.build();
// }
}

@ -52,8 +52,16 @@ public class AuthTokenFilter extends OncePerRequestFilter {
filterChain.doFilter(request, response);
}
private String parseJwt(HttpServletRequest request) {
String jwt = jwtUtils.getJwtFromCookies(request);
return jwt;
}
private String parseJwt(HttpServletRequest request) {
// 쿠키에서 JWT 가져오기
String jwt = jwtUtils.getJwtFromCookies(request);
if (jwt != null) {
return jwt;
}
// 헤더에서 JWT 가져오기
jwt = request.getHeader("cuuva-jwt");
return (jwt != null && !jwt.isEmpty()) ? jwt : null;
}
}

@ -0,0 +1,61 @@
package kr.re.etri.autoflow.service;
import kr.re.etri.autoflow.models.RefreshToken;
import kr.re.etri.autoflow.payload.request.LoginRequest;
import kr.re.etri.autoflow.payload.response.UserInfoResponse;
import kr.re.etri.autoflow.security.jwt.JwtUtils;
import kr.re.etri.autoflow.security.services.RefreshTokenService;
import kr.re.etri.autoflow.security.services.UserDetailsImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseCookie;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
@RequiredArgsConstructor
public class AuthService {
private final AuthenticationManager authenticationManager;
private final JwtUtils jwtUtils;
private final RefreshTokenService refreshTokenService;
public Map<String, Object> authenticate(LoginRequest request) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
);
SecurityContextHolder.getContext().setAuthentication(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
// 기존 refresh token 제거
refreshTokenService.deleteByUserId(userDetails.getId());
// 새 JWT 및 RefreshToken 생성
ResponseCookie jwtCookie = jwtUtils.generateJwtCookie(userDetails);
RefreshToken refreshToken = refreshTokenService.createRefreshToken(userDetails.getId());
ResponseCookie jwtRefreshCookie = jwtUtils.generateRefreshJwtCookie(refreshToken.getToken());
UserInfoResponse userInfo = new UserInfoResponse(
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.toList()
);
Map<String, Object> response = new HashMap<>();
response.put("userInfo", userInfo);
response.put("jwtCookie", jwtCookie.toString());
response.put("jwtRefreshCookie", jwtRefreshCookie.toString());
return response;
}
}

@ -40,6 +40,7 @@ public class OpenAPIConfig {
.addSecuritySchemes(SECURITY_SCHEME_ACCESS,
new SecurityScheme()
.name("cuuva-jwt") // 액세스 토큰 쿠키 이름
.bearerFormat("JWT")
.type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER)
)

Loading…
Cancel
Save