将 Spring 引导和 OAuth2 客户端从使用客户端凭据流程转换为授权代码授予流程

Convert Spring Boot and OAuth2 client from using Client Credentials flow to Authorization Code Grant flow

我一直在努力创建一个使用 OAuth 2.0 授权代码授予流程的示例客户端。

我能够成功使用客户端凭据流程,但是当我尝试使用授权代码流程时,我没有被重定向到正确的 uri。

当调用 OAuth2RestTmplate.exchange 方法时,我在 RestTemplate.doExecute(...) 方法中得到一个重定向异常。它从 finally 子句中抛出。 响应为空,但 if 没有停止它。

finally {
            if (response != null) {
                response.close();
            }

我仍然收到登录和授权提示,但没有定向到包含数据的响应。我刚刚被重定向回客户端主页。 Postman 使用具有相同客户端凭据的授权代码流进行的相同调用成功,因此我知道客户端注册是正确的。

我可以用另一双眼睛看看我错过了什么。提前致谢!以下是我的代码摘录。

使用 oauth2 客户端凭据流的工作客户端:

客户端应用:

@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class})
public class ClientExampleClientCredentials extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(ClientExampleClientCredentials.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(ClientExampleClientCredentials.class);
    }
}

控制器:

@RestController
public class HomeController {

    @Value("${security.oauth2.client.clientId}")
    private String clientId;

    @Value("${security.oauth2.client.clientSecret}")
    private String clientSecret;

    @Value("${security.oauth2.client.apiUrl}")
    private String apiUrl;

    @Value("${security.oauth2.client.scope}")
    private List<String> scopes;

    @Value("${security.oauth2.client.accessTokenUri}")
    private String accessTokenUri;


    /**
     * Example of using the OAuth2RestTemplate to access external resources
     *
     * The OAuth2RestTemplate takes care of exchanging credentials with the auth server, as well as adding the
     * bearer token to each request to the FHIR services.
     *
     */
    @RequestMapping("/ex-1")
    public String retrievePatientByIdUsingRestTemplate(@RequestParam String id) {
        OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(getClientCredentialsResourceDetails(), new DefaultOAuth2ClientContext());
        ResponseEntity<String> response = oAuth2RestTemplate.exchange(apiUrl + "/Patient/" + id, HttpMethod.GET, null, String.class);
        String responseBody = response.getBody();
        return responseBody;
    }

    private ClientCredentialsResourceDetails getClientCredentialsResourceDetails() {
        ClientCredentialsResourceDetails clientCredentialsResourceDetails = new ClientCredentialsResourceDetails();

        clientCredentialsResourceDetails.setAccessTokenUri(accessTokenUri);
        clientCredentialsResourceDetails.setAuthenticationScheme(AuthenticationScheme.header);
        clientCredentialsResourceDetails.setClientId(clientId);
        clientCredentialsResourceDetails.setClientSecret(clientSecret);
        clientCredentialsResourceDetails.setScope(scopes);

        return clientCredentialsResourceDetails;
    }
}

application.yml

security:
    oauth2:
        client:
            clientId: client_id
            clientSecret: secret
            apiUrl: http://localhost:8080/testData/data
            accessTokenUri: http://localhost:8080/test-auth/token  
            scope: system/*.read

这对我进行身份验证非常有效,然后重定向到我的服务 url。但是,授权代码流程不起作用。

使用 oauth2 授权代码流程的客户端损坏:

客户端应用程序:

@SpringBootApplication (exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class})
public class ClientExampleAccessToken extends SpringBootServletInitializer  {

    public static void main(String[] args) {
        SpringApplication.run(ClientExampleAccessToken.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(ClientExampleAccessToken.class);
    }

}

控制器:

package org.ihc.clinical.controller;

@Configuration
@EnableOAuth2Client
@RestController
public class HomeController {

    @Value("${security.oauth2.client.clientId}")
    private String clientId;

    @Value("${security.oauth2.client.clientSecret}")
    private String clientSecret;

    @Value("${security.oauth2.client.accessTokenUri}")
    private String accessTokenUri;

    @Value(("${security.oauth2.client.userAuthorizationUri}"))
    private String userAuthorizationUri;

    @Value("${security.oauth2.client.apiUrl}")
    private String apiUrl;

    @Value("${security.oauth2.client.redirectUri}")
    private String redirectUri;


    @RequestMapping("/ex-1")
    public String retrievePatientByIdUsingRestTemplate(@RequestParam String empi) {

        OAuth2ProtectedResourceDetails resource = resource();
        String path = apiUrl + "/Patient/" + empi;
        OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(resource, new DefaultOAuth2ClientContext());

        ***/*error occurs here in RestTemplate.doExcute.  error:org.springframework.security.oauth2.client.resource.UserRedirectRequiredException: 
        A redirect is required to get the users approval */***  
        ResponseEntity<String> response = oAuth2RestTemplate.exchange(path, HttpMethod.GET, null, String.class);

        //AuthorizationCodeAccessTokenProvider provider = new //AuthorizationCodeAccessTokenProvider();
        //Token Request
        //AccessTokenRequest request = new DefaultAccessTokenRequest();
        //String code = provider.obtainAuthorizationCode(resource, request);
        //request.setAuthorizationCode(code);
        //OAuth2AccessToken oAuth2AccessToken = //provider.obtainAccessToken(resource, request);

        //Token Response
        //String tokenValue = oAuth2AccessToken.getValue();
        //return tokenValue;
    }

    //Call when ready to send token Request
    private OAuth2ProtectedResourceDetails resource() {
        AuthorizationCodeResourceDetails authorizationCodeResourceDetails = new AuthorizationCodeResourceDetails();
        authorizationCodeResourceDetails.setClientId(clientId);
        authorizationCodeResourceDetails.setClientSecret(clientSecret);
        authorizationCodeResourceDetails.setAccessTokenUri(accessTokenUri);
        authorizationCodeResourceDetails.setUserAuthorizationUri(userAuthorizationUri);
        //authorizationCodeResourceDetails.setScope(scopes);
        authorizationCodeResourceDetails.setPreEstablishedRedirectUri(redirectUri);

        return authorizationCodeResourceDetails;
    }

}

application.yml

  security:
    oauth2:
      client:
        clientId: clientid
        clientSecret: secret
        accessTokenUri: http://localhost:8080/test-auth/token
        userAuthorizationUri: http://localhost:8080/test-auth/authorize
        apiUrl: http://localhost:8080/test-fhir-cdr/data
        redirectUri: http://localhost:8080/test-examples-access-token

我终于在这里找到了解决方案:https://projects.spring.io/spring-security-oauth/docs/oauth2.html

我需要将以下代码添加到控制器中:

 @Autowired
    private OAuth2ClientContext oauth2Context;

    @Bean
    public OAuth2RestTemplate getOauth2RestTemplate() {
        return new OAuth2RestTemplate(resource(), oauth2Context);
    }

然后像下面这样调用 getOauth2RestTemplate():

@RequestMapping("/ex-1")
public String retrievePatientByIdUsingRestTemplate(@RequestParam String empi) {

String path = apiUrl + "/Patient/" + empi;
OAuth2RestTemplate oAuth2RestTemplate = getOauth2RestTemplate();

ResponseEntity<String> response = oAuth2RestTemplate.exchange(path, HttpMethod.GET, null, String.class);

return response.getBody();

}