Spring Security 5.2 密码流程

spc*_*670 6 spring spring-security oauth-2.0 spring-security-oauth2

我正在尝试使用最新版本的 Spring Security - 5.2 中的密码流对用户进行身份验证。

文档似乎建议如何做到这一点。

@Bean
public OAuth2AuthorizedClientManager passwordFlowAuthorizedClientManager(
        HttpClient httpClient,
        ClientRegistrationRepository clientRegistrationRepository,
        OAuth2AuthorizedClientRepository authorizedClientRepository) {

    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);

    DefaultPasswordTokenResponseClient c = new DefaultPasswordTokenResponseClient();
    RestTemplate client = new RestTemplate(requestFactory);
    client.setMessageConverters(Arrays.asList(
            new FormHttpMessageConverter(),
            new OAuth2AccessTokenResponseHttpMessageConverter()));
    client.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
    c.setRestOperations(client);

    OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
                .password(configurer -> configurer.accessTokenResponseClient(c))
                .refreshToken()
                .build();

    DefaultOAuth2AuthorizedClientManager authorizedClientManager =
            new DefaultOAuth2AuthorizedClientManager(
                    clientRegistrationRepository, authorizedClientRepository);
    authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

    authorizedClientManager.setContextAttributesMapper(authorizeRequest -> {
        Map<String, Object> contextAttributes = new HashMap<>();
        String username = authorizeRequest.getAttribute(OAuth2ParameterNames.USERNAME);
        String password = authorizeRequest.getAttribute(OAuth2ParameterNames.PASSWORD);
        contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username);
        contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password);
        return contextAttributes;
    });

    return authorizedClientManager;
}



Run Code Online (Sandbox Code Playgroud)

我执行请求,可以看到 HTTP 标头中返回的访问令牌,但 SecurityContext 未填充,并且会话用户保持匿名。

String username = "joe";
String password = "joe";
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
ClientRegistration r = clientRegistrationRepository.findByRegistrationId("keycloak");

OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId(r.getRegistrationId())
        .principal(authentication)
        .attributes(attrs -> {
            attrs.put(OAuth2ParameterNames.USERNAME, username);
            attrs.put(OAuth2ParameterNames.PASSWORD, password);
        })
        .build();
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

spc*_*670 3

在阅读了更多文档后,我认为 Spring Security 5.2 中的 Oauth 2 密码流不受与授权流相同的支持。Spring Security 5.2 为 http 客户端提供了密码流支持,可以缓存授权请求并在令牌过期之前刷新令牌 - 但没有最终用户密码流支持,其中客户端将凭证代理到授权服务器。

当然,完全可以通过获取凭据来对最终用户进行身份验证,实现一个自定义的 AuthenticationProvider,该 AuthenticationProvider 将凭据与授权服务器交换为令牌,并返回持久保存到上下文的 OAuth2AuthenticationToken。

  • 该主题或任何代码示例有更多进展吗?对于我正在从事的项目来说,这正是我所需要的。我试图了解我是否应该这样做,但找不到我不应该这样做的理由。如果是这样,Spring项目考虑这个问题并可能在项目中实现可能是件好事。 (2认同)