class OAuth2AuthenticationSuccessHandler(
private val tokenProvider: JwtTokenProvider,
private val objectMapper: ObjectMapper,
private val userRepository: UserRepository,
) : SimpleUrlAuthenticationSuccessHandler() {
@Throws(IOException::class)
override fun onAuthenticationSuccess(
request: HttpServletRequest,
response: HttpServletResponse,
authentication: Authentication
) {
val oAuth2User = authentication.principal as OAuth2User
val username = oAuth2User.name // OAuth2 인증으로부터 사용자 식별 정보 추출
val userEntity = userRepository.findByUserName("kakao-$username") ?: throw RuntimeException("User not found")
val authResponse = OAuth2AuthenticationResponse(
userName = userEntity?.userName ?: "",
passWord = userEntity?.password ?: ""
)
response.addHeader("Authorization", "Bearer " + tokenProvider.createToken(authResponse.userName))
response.contentType = "application/json;charset=UTF-8"
response.writer.write(objectMapper.writeValueAsString(authResponse))
}
}
success handler 부분이고 최종적으로 생성된 유저 네임과 패스워드를 안드로이드에 전달해주기 위해 json으로 파싱해서 넘겨주는 부분입니다
@Service
class CustomOAuth2UserService(
private val userRepository: UserRepository,
private val userSignUpService: UserSignUpService,
private val userSignInService: UserSignInService,
) : DefaultOAuth2UserService() {
private val logger: Logger = LoggerFactory.getLogger(CustomOAuth2UserService::class.java)
override fun loadUser(userRequest: OAuth2UserRequest): OAuth2User {
// OAuth2UserRequest를 통해 카카오에서 사용자 정보를 로드
val oAuth2User = super.loadUser(userRequest)
logger.info(“{}”, oAuth2User.attributes)
// 카카오에서 제공하는 사용자 정보를 추출
val attributes = oAuth2User.attributes
val kakaoId = ("" + attributes["id"]) as? String ?: ""
if (kakaoId.isNotEmpty()) {
val userName = "kakao-$kakaoId"
val existingUser = userRepository.findByUserName(userName)
if (existingUser == null) {
// 사용자가 존재하지 않으면 회원가입
userSignUpService.signUp(userName = userName, password = "0000", email = "")
val newUser = userRepository.findByUserName(userName)
if (newUser != null) {
val userResponse = userSignInService.localSignIn(newUser.userName, newUser.password)
} else {
throw UserNotFoundException()
}
} else {
// 이미 존재하는 사용자라면 필요한 경우 로그인 처리
val userResponse = userSignInService.localSignIn(existingUser.userName, existingUser.password)
}
}
return oAuth2User
}
}
서비스 로직입니다
@Bean @Throws(Exception::class)
fun filterChain(http: HttpSecurity): SecurityFilterChain {
http
.httpBasic { it → it.disable() }
.csrf { it → it.disable() }
.sessionManagement { it → it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) }
.authorizeHttpRequests { it →
it
.requestMatchers(“/“).permitAll()
.requestMatchers(”/welcome").permitAll()
.requestMatchers(“/api/signup”).permitAll()
.requestMatchers(“/api/signin”).permitAll()
.requestMatchers(“/test-page”).permitAll()
.requestMatchers("/swagger-ui/”).permitAll()
.requestMatchers(“/v3/api-docs/**”).permitAll()
.anyRequest().authenticated()
}
.addFilterBefore(JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter::class.java)
// 소셜 로그인
.oauth2Login {
it.userInfoEndpoint {
it.userService(customOAuth2UserService)
}
.successHandler(OAuth2AuthenticationSuccessHandler(jwtTokenProvider, ObjectMapper(), userRepository))
}
return http.build()
}
시큐리티 설정 부분입니다
로컬에서는 제대로 가입도 되고 json도 넘어오는데 서버에서는 401에러가 나옵니다