oAuth2 client with password grant in Spring Security

前端 未结 1 574
青春惊慌失措
青春惊慌失措 2021-02-04 17:04

I\'m consuming a set of oAuth2 protected services. It currently works like this: the client logs in using their username and password. I exchange these for a token. I keep the t

1条回答
  •  礼貌的吻别
    2021-02-04 17:29

    I've mashed a similar solution from browsing the Spring Security OAuth sources and bits and pieces of other solutions found online. I'm using Java Config but maybe it can help you map to a xml configuration, here it goes:

    @Configuration
    @EnableOAuth2Client
    public class RestClientConfig {
    
        @Value("${http.client.maxPoolSize}")
        private Integer maxPoolSize;
    
        @Value("${oauth2.resourceId}")
        private String resourceId;
    
        @Value("${oauth2.clientId}")
        private String clientId;
    
        @Value("${oauth2.clientSecret}")
        private String clientSecret;
    
        @Value("${oauth2.accessTokenUri}")
        private String accessTokenUri;
    
    
        @Autowired
        private OAuth2ClientContext oauth2ClientContext;
    
    
        @Bean
        public ClientHttpRequestFactory httpRequestFactory() {
            return new HttpComponentsClientHttpRequestFactory(httpClient());
        }
    
        @Bean
        public HttpClient httpClient() {
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
            connectionManager.setMaxTotal(maxPoolSize);
            // This client is for internal connections so only one route is expected
            connectionManager.setDefaultMaxPerRoute(maxPoolSize);
            return HttpClientBuilder.create().setConnectionManager(connectionManager).build();
        } 
    
        @Bean
        public OAuth2ProtectedResourceDetails oauth2ProtectedResourceDetails() {
            ResourceOwnerPasswordResourceDetails details = new ResourceOwnerPasswordResourceDetails();
            details.setId(resourceId);
            details.setClientId(clientId);
            details.setClientSecret(clientSecret);
            details.setAccessTokenUri(accessTokenUri);
            return details;
        }
    
        @Bean
        public AccessTokenProvider accessTokenProvider() {
            ResourceOwnerPasswordAccessTokenProvider tokenProvider = new ResourceOwnerPasswordAccessTokenProvider();
            tokenProvider.setRequestFactory(httpRequestFactory());
            return new AccessTokenProviderChain(
                      Arrays. asList(tokenProvider)
                    );
        }
    
        @Bean
        public OAuth2RestTemplate restTemplate() {
            OAuth2RestTemplate template = new OAuth2RestTemplate(oauth2ProtectedResourceDetails(), oauth2ClientContext);
            template.setRequestFactory(httpRequestFactory());
            template.setAccessTokenProvider(accessTokenProvider());
            return template;
        }   
    }
    

    One important bit I found is that you need to use the AccessTokenProviderChain even for a single Provider otherwise the automatic token refresh (after authentication) won't work.

    To set the user credentials on the first request you'll need this:

    @Autowired
    private OAuth2RestTemplate restTemplate;
    
    restTemplate.getOAuth2ClientContext().getAccessTokenRequest().set("username", username);
    restTemplate.getOAuth2ClientContext().getAccessTokenRequest().set("password", password);
    

    Then you can issue requests as normal using the RestTemplate methods, e.g:

        String url = "http://localhost:{port}/api/users/search/findByUsername?username={username}";
    
        ResponseEntity responseEntity = restTemplate.getForEntity(
                url, User.class, 8081, username);
    

    If you want to trace the requests on the wire you can set the log level on apache http client to DEBUG, e.g. with Spring Boot:

    logging.level.org.apache.http=DEBUG

    0 讨论(0)
提交回复
热议问题