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

jeyong·2024년 3월 20일
0

공부 / 생각 정리  

목록 보기
59/121


이번게시글에 다룰 내용은 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
노를 젓다 보면 언젠가는 물이 들어오겠지.

0개의 댓글

관련 채용 정보