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

时间:2016-10-21 23:32:30

标签: spring-boot oauth-2.0 spring-security-oauth2 resttemplate

在尝试创建使用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

这可以很好地验证我,然后重定向到我的服务网址。但是,授权代码流程不起作用。

使用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

1 个答案:

答案 0 :(得分:1)

我终于在这里找到了解决方案: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();

}