首页 文章

将Spring Boot和OAuth2客户端从使用Client Credentials流转换为Authorization Code Grant流

提问于
浏览
3

在尝试创建使用OAuth 2.0授权代码授权流程的示例客户端时,我一直在努力 .

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

调用OAuth2RestTmplate.exchange方法时,我在RestTemplate.doExecute(...)方法中获得重定向异常 . 它是从finally子句抛出的 . 响应为空,但if不会停止响应 .

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

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

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

Working client using oauth2 client credentials flow:

Client App

@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);
    }
}

Controller:

@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

这可以很好地验证我,然后重定向到我的服务网址 . 但是,授权代码流程无效 .

Broken client using oauth2 authorization code flow:

Client App:

@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);
    }

}

Controller:

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 回答

  • 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();
    

    }

相关问题