[공부정리] redirect_uri를 처리하는 AuthenticationFilter 구현하여 인가 처리

jeyong·2024년 3월 20일
0

공부 / 생각 정리  

목록 보기
59/120
post-custom-banner


이번게시글에 다룰 내용은 redirect_uri를 처리할 수 있는 Controller 또는 AuthenticationFilter를 직접 구현하여 서비스측의 인가 처리를 하는 과정이다. 무엇을 이야기하는 건지 잘 모르는 것이 정상이다. 아래 kakao Dev Talk을 읽고 오는 것을 추천한다.

Rest api와 javascript Spring Oauth2 카카오 로그인 시 302 리다이렉트 관련 문의

해당 문제를 해결하는 내용을 게시글에 작성할 예정이다.

1. 사전 지식

  • [Spring Security] Spring Security Oauth2 Client 분석
  • Spring Security OAuth2

    Spring Security Oauth2 Client의 동작 방식을 자세하게 정리해둔 게시글이다. 비록 나는 혼자 Spring Security의 동작 방식을 혼자 디버깅하면서 공부하고 발견한 게시글이지만, 처음 접한 사람은 이 게시글을 읽고 시작하는 것을 추천한다.

2. AuthenticationFilter 구현

나는 카카오에서 추천한대로 redirect_uri를 처리할 수 있는 AuthenticationFilter를 구현하여 문제를 해결하였다. 내가 구현한 AuthenticationFilter는 아래와 같다.

@RequiredArgsConstructor
public class PreOAuth2AuthorizationRequestFilter extends OncePerRequestFilter {

    private final ClientRegistrationRepository clientRegistrationRepository;
    private final AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        String state = request.getParameter(OAuth2ParameterNames.STATE);

        if (KAKAO_REDIRECT_URI.equals(requestURI) && IOS_STATE.equals(state)) {
            OAuth2AuthorizationRequest authorizationRequest = createAuthorizationRequest(request, state);
            if (authorizationRequest != null) {
                authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response);
            } else {
                throw new KakaoOauth2LoginFailureException("Failed to process OAuth2 authorization request");
            }
        }
        filterChain.doFilter(request, response);
    }

    private OAuth2AuthorizationRequest createAuthorizationRequest(HttpServletRequest request, String state) {
        ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(KAKAO_REGISTRATION_ID);
        if (clientRegistration == null) {
            return null;
        }

        OAuth2AuthorizationRequest.Builder builder = OAuth2AuthorizationRequest.authorizationCode()
                .clientId(clientRegistration.getClientId())
                .authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
                .redirectUri(expandRedirectUri(request, clientRegistration, "login"))
                .scopes(clientRegistration.getScopes())
                .state(state)
                .attributes(attributes -> {
                    attributes.put(OAuth2ParameterNames.REGISTRATION_ID, KAKAO_REGISTRATION_ID);
                });

        return builder.build();
    }

    private static String expandRedirectUri(HttpServletRequest request, ClientRegistration clientRegistration, String action) {
        Map<String, String> uriVariables = new HashMap<>();
        uriVariables.put("registrationId", clientRegistration.getRegistrationId());

        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
                .replacePath(request.getContextPath())
                .replaceQuery(null)
                .fragment(null)
                .build();

        String scheme = uriComponents.getScheme();
        uriVariables.put("baseScheme", (scheme != null) ? scheme : "");
        String host = uriComponents.getHost();
        uriVariables.put("baseHost", (host != null) ? host : "");

        int port = uriComponents.getPort();
        uriVariables.put("basePort", (port == -1) ? "" : ":" + port);
        String path = uriComponents.getPath();
        if (StringUtils.hasLength(path)) {
            if (path.charAt(0) != '/') {
                path = '/' + path;
            }
        }
        uriVariables.put("basePath", (path != null) ? path : "");
        uriVariables.put("baseUrl", uriComponents.toUriString());
        uriVariables.put("action", (action != null) ? action : "");

        return UriComponentsBuilder.fromUriString(clientRegistration.getRedirectUri())
                .buildAndExpand(uriVariables)
                .toUriString();
    }
}

DefaultOAuth2AuthorizationRequestResolver를 참고하여 구현하였으며, 로직 자체는 간단하다. 파라미터 중 "state" 값이 "ios"라면 AuthorizationRequestRepository에 kakao에 관련한 OAuth2AuthorizationRequest를 ClientRegistrationRepository를 이용하여 생성한뒤, 넣어주면 된다.

3. 쿠키를 이용한 해결

카카오 소셜 간편 로그인(javascript SDK) + spring oauth2 security 적용기

필터를 이용한 방식이 아닌, 쿠키를 이용한 해결방식도 있으니 참고해서 자신에게 맞는 방식을 적용해서 해결하기를 추천한다.

profile
노를 젓다 보면 언젠가는 물이 들어오겠지.
post-custom-banner

0개의 댓글