스프링 시큐리티를 이용하여 인증/인가 로직을 작성하며 인증은 성공했지만, 인가는 실패한 경우 카카오 로그인 화면이 리턴되는 오류가 발생하였습니다.
다음은 제 SecurityConfig.java 파일입니다.
// Spring Security 설정
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
...
.authorizeHttpRequests(
authorize -> authorize
.requestMatchers("/store/join", "/user/login", "/user/reissue", "/customer/join", "/login/oauth2/**").permitAll()
.requestMatchers("/user/logout", "/customer/info").authenticated()
.requestMatchers("/coupon", "/coupon/stop/**", "/coupon/finish").hasAuthority(UserType.STORE.getName())
.requestMatchers("/coupon/issue","/coupon/**").hasAuthority(UserType.CUSTOMER.getName())
.anyRequest().authenticated()
)
.oauth2Login((oauth2) -> {
oauth2
.userInfoEndpoint((endpoint) -> endpoint.userService(customOAuth2UserService));
oauth2.successHandler(oAuth2AuthenticationSuccessHandler);
oauth2.failureHandler(oAuth2AuthenticationFailureHandler);
})
;
return http.build();
}
}
예를 들어서, "/coupon" 이라는 API를 CUSTOMER 유저가 보내도록 해보겠습니다. 그렇게 되면 예상 로직은 JwtFilter를 통해 인증단계를 거친 후, SpringSecurity를 내 필터를 통해 인가 작업을 합니다. 이 때, 인가가 되지 않기 때문에 403에러를 발생시켜야 합니다.
하지만 제 리턴 결과는 다음과 같았습니다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport"
content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, width=device-width">
<meta name="next-head-count" content="2">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta content="website" property="og:type">
<meta content="카카오계정" property="og:title">
<meta content="https://accounts.kakaocdn.net/images/og_kakao.png" property="og:image">
<script type="text/javascript" src="//t1.daumcdn.net/tiara/js/v1/tiara.min.js" defer></script>
<link rel="preload" href="https://accounts.kakaocdn.net/_next/static/css/c02e46991717addb.css" as="style">
<link rel="stylesheet" href="https://accounts.kakaocdn.net/_next/static/css/c02e46991717addb.css" data-n-g="">
<link rel="preload" href="https://accounts.kakaocdn.net/_next/static/css/66a727ed600e6865.css" as="style">
<link rel="stylesheet" href="https://accounts.kakaocdn.net/_next/static/css/66a727ed600e6865.css" data-n-p="">
<link rel="preload" href="https://accounts.kakaocdn.net/_next/static/css/8493bcbffbf0b5be.css" as="style">
<link rel="stylesheet" href="https://accounts.kakaocdn.net/_next/static/css/8493bcbffbf0b5be.css" data-n-p="">
<noscript data-n-css=""></noscript>
<script defer nomodule="" src="https://accounts.kakaocdn.net/_next/static/chunks/polyfills-5cd94c89d3acac5f.js">
</script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/webpack-c518d6630e528dd6.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/framework-f8115f7fae64930e.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/main-a7d45bce11193232.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/pages/_app-91ac83647fe8a97f.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/29107295-f5d3d9a71e7e292a.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/70368-58b0a348debb6a04.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/69695-9ee32dd2295c9b6f.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/74534-ef40f6ad4c13b9c2.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/35999-9285c692bdc44fb2.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/3889-0f1ee3f4696c083c.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/chunks/pages/login/login-2c5b9572ffda1957.js" defer>
</script>
<script src="https://accounts.kakaocdn.net/_next/static/zEAT7DHzOrUgp8stG7ZY8/_buildManifest.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/zEAT7DHzOrUgp8stG7ZY8/_ssgManifest.js" defer></script>
<script src="https://accounts.kakaocdn.net/_next/static/zEAT7DHzOrUgp8stG7ZY8/_middlewareManifest.js" defer>
</script>
</head>
<body class="os_other pc type_responsive">
<div id="__next" data-reactroot=""></div>
<script id="__NEXT_DATA__" type="application/json">
{"props":{"pageProps":{"pageContext":{"commonContext":{"locale":"ko","uaClass":"os_other pc","responsiveView":true,"responsivePopup":false,"mobile":false,"webview":{"app":"web","webViewType":"none","appVersion":"","os":"other","osVersion":"","supportFilePicker":true,"supportExecUrlScheme":false,"supportMarketUrlScheme":true,"supportNavigation":false},"supportRefererMetaTag":false,"showHeader":false,"showFooter":true,"linkParams":{},"showDarkMode":null,"_csrf":"c569cdca-ec63-4648-aed2-f96e17b86fea","kage_file_max_size":100,"upload_kage_url":"https://up-api1-kage.kakao.com/up/kaccount-p/","p":"LMgrlTFOBaD0RT7kpjUd24G-V4p0FAoXSZj0rYezd2Q"},"context":{"webType":"web","defaultEmail":null,"showStaySignIn":true,"defaultStaySignIn":false,"appendStaySignedIn":false,"defaultCountryCode":"KR_82","showQrLogin":true,"showWebTalkLogin":false,"showDeviceFormLogin":false,"needCaptcha":false,"showIpSecurity":false,"loginUrl":"/login?continue=https%3A%2F%2Fkauth.kakao.com%2Foauth%2Fauthorize%3Fscope%3Dprofile_nickname%2520profile_image%2520account_email%26response_type%3Dcode%26state%3DtGLD1-U9H-Hz74gNTdALLzXFo-_ZUdYlO3kTYyUw3Ok%253D%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A8080%252Flogin%252Foauth2%252Fcode%252Fkakao%26through_account%3Dtrue%26client_id%3D56e7a5438fdb08baa0c60c5e42ff7a62","continueUrl":"https://kauth.kakao.com/oauth/authorize?scope=profile_nickname%20profile_image%20account_email&response_type=code&state=tGLD1-U9H-Hz74gNTdALLzXFo-_ZUdYlO3kTYyUw3Ok%3D&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Flogin%2Foauth2%2Fcode%2Fkakao&through_account=true&client_id=56e7a5438fdb08baa0c60c5e42ff7a62","useSimpleLogin":true,"exceedSimpleLoginLimit":false,"defaultSaveSignIn":false,"isTalkLoginError":false,"linkParams":{"lang":["ko"]},"requests":{"check_daum_sso":["get","https://logins.daum.net/accounts/endpoint/favicon.ico"]},"bannerImageUrl":null}}}},"page":"/login/login","query":{},"buildId":"zEAT7DHzOrUgp8stG7ZY8","assetPrefix":"https://accounts.kakaocdn.net","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}
</script>
</body>
</html>
또한, HttpStatus도 200이 나왔습니다. 이를 통해, API에서 인가가 되지 않는다면, 소셜로그인 필터가 실행됨을 확인할 수 있었습니다.
이는 정상로직이 아니기 때문에 소셜로그인이 아닌, 403 Forbidden을 리턴하도록 해야합니다.
해결방안
// Spring Security 설정
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
...
.authorizeHttpRequests(
authorize -> authorize
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll() // 인가 안되면 자체 시큐리티 타는데 -> 이거 막아주는 로직
.requestMatchers("/store/join", "/user/login", "/user/reissue", "/customer/join", "/login/oauth2/**").permitAll()
.requestMatchers("/user/logout", "/customer/info").authenticated()
.requestMatchers("/coupon", "/coupon/stop/**", "/coupon/finish").hasAuthority(UserType.STORE.getName())
.requestMatchers("/coupon/issue","/coupon/**").hasAuthority(UserType.CUSTOMER.getName())
.anyRequest().authenticated()
)
...
;
return http.build();
}
}
다음과 같이 .authorizeHttpRequests 의 requestMatchers 상단에 다음 코드를 추가해주면 됩니다.
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
그러면 결과가 정상적으로 나오는 것을 확인할 수 있습니다.
{
"timestamp": "2024-05-17T11:21:04.573+00:00",
"status": 403,
"error": "Forbidden",
"message": "Forbidden",
"path": "/coupon"
}
'프로젝트' 카테고리의 다른 글
[Spring] entity 변경해도 update 쿼리 안날라가는 이슈 (0) | 2024.05.28 |
---|---|
[AWS/S3] Spring에서 S3에 데이터 저장하기 (0) | 2024.05.19 |
[CS] WebSocket이란 ? (0) | 2024.04.23 |
[채팅] Spring Security + WebSocket 연결하기 (0) | 2024.02.22 |
[Spring Security/OAuth/React-Native] 스프링 시큐리티 OAuth와 리액트 네이티브를 이용하여 카카오 소셜 로그인 구현하기 (0) | 2024.01.16 |