인프런 커뮤니티 질문&답변

작성자 없음

작성자 정보가 삭제된 글입니다.

스프링 시큐리티 OAuth2

DefaultOAuth2AuthorizedClientManager - Client Credentials 권한 부여 구현하기

client-credentials 방식 accessToken null 이슈

작성

·

92

·

수정됨

0

Cannot invoke "org.springframework.security.oauth2.client.OAuth2AuthorizedClient.getAccessToken()" because "oAuth2AuthorizedClient" is null] with root cause

keycloak 버전은 : 21.1.2

 

@GetMapping("/oauth2Login")
public String oauth2Login(Model model, HttpServletRequest request, HttpServletResponse response) {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    OAuth2AuthorizeRequest oAuth2AuthorizeRequest = OAuth2AuthorizeRequest
            .withClientRegistrationId("keycloak")
            .principal(authentication)
            .attribute(HttpServletRequest.class.getName(), request)
            .attribute(HttpServletResponse.class.getName(), response)
            .build();

    OAuth2AuthorizationSuccessHandler successHandler = (authorizedClient, principal, attributes) -> {
        oAuth2AuthorizedClientRepository
            .saveAuthorizedClient(authorizedClient, principal,
                    (HttpServletRequest) attributes.get(HttpServletRequest.class.getName()),
                    (HttpServletResponse) attributes.get(HttpServletResponse.class.getName()));

        System.out.println("authorizedClient : " + authorizedClient);
        System.out.println("principal : " + principal);
        System.out.println("attributes : " + attributes);
    };

    auth2AuthorizedClientManager.setAuthorizationSuccessHandler(successHandler);

    OAuth2AuthorizedClient oAuth2AuthorizedClient = auth2AuthorizedClientManager.authorize(oAuth2AuthorizeRequest);

    model.addAttribute("oAuth2AuthorizedClient", oAuth2AuthorizedClient.getAccessToken().getTokenValue());

    return "home";
}

 

keycloak:
  clientId: oauath2-client-app
  clientSecret: HPWAsKr9dEy9DPU1babedRmpstowiXOs
  clientName: oauath2-client-app
  authorizationGrantType: client-credentials
  clientAuthenticationMethod: client_secret_basic
  provider: keycloak

 

<form sec:authorize="isAnonymous()" action="#">
    <p><input type="button" onclick="authorizationCode()" value="AuthorizationCode Grant"/></p>
    <p><div sec:authorize="isAnonymous()"><a th:href="@{/oauth2Login(username='user',password='1234')}">Password flow</a></div></p>
    <div sec:authorize="isAnonymous()"><a th:href="@{/oauth2Login}">Client Credentials Flow Login</a></div>
</form>

 

@Configuration
public class AppConfig {

    @Bean
    public DefaultOAuth2AuthorizedClientManager auth2AuthorizedClientManager(ClientRegistrationRepository clientRegistrationRepository,
                                                                      OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository) {

        OAuth2AuthorizedClientProvider oAuth2AuthorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
                .authorizationCode()
                .password()
                .clientCredentials()
                .refreshToken()
                .build();

        DefaultOAuth2AuthorizedClientManager defaultOAuth2AuthorizedClientManager = new DefaultOAuth2AuthorizedClientManager(clientRegistrationRepository, oAuth2AuthorizedClientRepository);

        defaultOAuth2AuthorizedClientManager.setAuthorizedClientProvider(oAuth2AuthorizedClientProvider);
        defaultOAuth2AuthorizedClientManager.setContextAttributesMapper(contextAttributeManager());

        return defaultOAuth2AuthorizedClientManager;
    }

    private Function<OAuth2AuthorizeRequest, Map<String, Object>> contextAttributeManager() {
        return oAuth2AuthorizeRequest -> {
            Map<String, Object> contextAttributes = new HashMap<>();
            HttpServletRequest httpServletRequest = oAuth2AuthorizeRequest.getAttribute(HttpServletRequest.class.getName());
            String userName = httpServletRequest.getParameter(OAuth2ParameterNames.USERNAME);
            String userPassword = httpServletRequest.getParameter(OAuth2ParameterNames.PASSWORD);

            if(StringUtils.hasText(userName) && StringUtils.hasText(userPassword)) {
                contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, userName);
                contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, userPassword);
            }

            return contextAttributes;
        };
    }
}

 

이렇게 됩니다. 현재 상황으로 문제가 되어 있는 부분이 없는 것 같습니다.

어디부터 다시 확인해야 될지 조언 부탁드립니다.

답변 1

0

안녕하세요, 인프런 AI 인턴입니다.

JUNI님의 코드와 설정을 검토해 본 결과, client-credentials 방식과 관련하여 문제를 겪고 계신 것으로 보입니다. client-credentials 그랜트 타입은 클라이언트가 서버에 직접 인증하는 상황에 사용되며, 일반적으로 사용자와 관련된 권한이 아닌 클라이언트 자체의 권한에 대해 적용됩니다. 하지만 주신 코드는 사용자 인증을 기반으로 하는 코드로 보입니다.

client-credentials 방식으로 액세스 토큰을 얻으려면, 먼저 OAuth2AuthorizedClientManagerOAuth2AuthorizedClientProvider에서 client-credentials 방식을 지원하도록 설정되어 있어야 합니다. 또한, 사용자 인증 과정이 아니므로 Authentication 객체 없이 클라이언트 인증 정보만으로 액세스 토큰을 요청해야 합니다.

현재 제공하신 내용에는 OAuth2AuthorizedClientManagerOAuth2AuthorizedClientProvider의 설정 관련 내용이 누락되어 있습니다. 따라서 다음을 확인해 주세요:

  1. OAuth2AuthorizedClientManager와 어떻게 설정되어 있는지, 특히 client-credentials를 처리할 수 있는 OAuth2AuthorizedClientProvider가 포함되어 있는지 확인하세요.
  2. client-credentials 사용 시 Authentication 객체 대신 클라이언트의 인증 정보만을 사용하여 토큰을 요청하는 코드로 변경이 필요할 수 있습니다.

프로그램의 나머지 부분에 오류가 없다면 이 점을 검토하셔서 문제를 해결해 보시기 바랍니다.

작성자 없음

작성자 정보가 삭제된 글입니다.

질문하기