如何配置@ EnableOAuth2Client与@EnableResourceServer一起使用?

时间:2019-04-09 16:15:39

标签: spring-boot spring-security spring-security-oauth2

如果我在春季启动应用程序中添加注释@EnableResourceServer,则OAuth2客户端将无法再使用。

如果我发送以下请求

curl -X GET \
  http://localhost:5050/api/user \
  -H 'Authorization: Bearer eyJhbGciOiJSUzI1N...' \
  -H 'Postman-Token: a178bb65-1cba-4765-ac6b-ced90c49c50f' \
  -H 'cache-control: no-cache'

然后我得到答复

{
    "timestamp": "2019-04-10T12:13:26.294+0000",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/"
}

但我希望

Client internal-backend has obtained token
eyJhbGciOiJSU... to request protected resource.

在这里您可以看到我的控制台输出:

...
2019-04-10 14:25:42.918 DEBUG 65661 --- [nio-5050-exec-1] o.s.security.web.FilterChainProxy        : /api/user at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2019-04-10 14:25:42.918 DEBUG 65661 --- [nio-5050-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /api/user; Attributes: [#oauth2.throwOnError(authenticated)]
2019-04-10 14:25:42.918 DEBUG 65661 --- [nio-5050-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.oauth2.provider.OAuth2Authentication@5548a18e: Principal: alan; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=0:0:0:0:0:0:0:1, tokenType=BearertokenValue=<TOKEN>; Not granted any authorities
2019-04-10 14:25:42.922 DEBUG 65661 --- [nio-5050-exec-1] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@4f7c3786, returned: 1
2019-04-10 14:25:42.922 DEBUG 65661 --- [nio-5050-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorization successful
2019-04-10 14:25:42.922 DEBUG 65661 --- [nio-5050-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : RunAsManager did not change Authentication object
2019-04-10 14:25:42.923 DEBUG 65661 --- [nio-5050-exec-1] o.s.security.web.FilterChainProxy        : /api/user reached end of additional filter chain; proceeding with original chain
2019-04-10 14:25:42.969 DEBUG 65661 --- [nio-5050-exec-1] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@27b01c2c
2019-04-10 14:25:42.969 DEBUG 65661 --- [nio-5050-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2019-04-10 14:25:42.971 DEBUG 65661 --- [nio-5050-exec-1] o.s.s.web.DefaultRedirectStrategy        : Redirecting to 'http://localhost:9090/auth/realms/prototype/protocol/openid-connect/auth?client_id=internal-backend&redirect_uri=http://localhost:5050/callback&response_type=code&state=Duk9bz'
2019-04-10 14:25:42.981 DEBUG 65661 --- [nio-5050-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/callback'; against '/api/**'
2019-04-10 14:25:42.982 DEBUG 65661 --- [nio-5050-exec-3] o.s.security.web.FilterChainProxy        : /callback?state=Duk9bz&session_state=885cb558-b19c-4610-8db7-be0c3193e33f&code=f1edb261-bca0-4034-a1cb-508e8516bf39.885cb558-b19c-4610-8db7-be0c3193e33f.e054618b-8ea5-410e-ad95-401195d7f027 at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2019-04-10 14:25:42.982 DEBUG 65661 --- [nio-5050-exec-3] o.s.security.web.FilterChainProxy        : /callback?state=Duk9bz&session_state=885cb558-b19c-4610-8db7-be0c3193e33f&code=f1edb261-bca0-4034-a1cb-508e8516bf39.885cb558-b19c-4610-8db7-be0c3193e33f.e054618b-8ea5-410e-ad95-401195d7f027 at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2019-04-10 14:25:42.982 DEBUG 65661 --- [nio-5050-exec-3] w.c.HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
2019-04-10 14:25:42.982 DEBUG 65661 --- [nio-5050-exec-3] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@4384b0e7. A new one will be created.
2019-04-10 14:25:42.983 DEBUG 65661 --- [nio-5050-exec-3] o.s.security.web.FilterChainProxy        : /callback?state=Duk9bz&session_state=885cb558-b19c-4610-8db7-be0c3193e33f&code=f1edb261-bca0-4034-a1cb-508e8516bf39.885cb558-b19c-4610-8db7-be0c3193e33f.e054618b-8ea5-410e-ad95-401195d7f027 at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2019-04-10 14:25:42.983 DEBUG 65661 --- [nio-5050-exec-3] o.s.security.web.FilterChainProxy        : /callback?state=Duk9bz&session_state=885cb558-b19c-4610-8db7-be0c3193e33f&code=f1edb261-bca0-4034-a1cb-508e8516bf39.885cb558-b19c-4610-8db7-be0c3193e33f.e054618b-8ea5-410e-ad95-401195d7f027 at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
2019-04-10 14:25:42.984 DEBUG 65661 --- [nio-5050-exec-3] o.s.security.web.FilterChainProxy        : /callback?state=Duk9bz&session_state=885cb558-b19c-4610-8db7-be0c3193e33f&code=f1edb261-bca0-4034-a1cb-508e8516bf39.885cb558-b19c-4610-8db7-be0c3193e33f.e054618b-8ea5-410e-ad95-401195d7f027 at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2019-04-10 14:25:42.984 DEBUG 65661 --- [nio-5050-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /callback' doesn't match 'POST /logout'
2019-04-10 14:25:42.984 DEBUG 65661 --- [nio-5050-exec-3] o.s.security.web.FilterChainProxy        : /callback?state=Duk9bz&session_state=885cb558-b19c-4610-8db7-be0c3193e33f&code=f1edb261-bca0-4034-a1cb-508e8516bf39.885cb558-b19c-4610-8db7-be0c3193e33f.e054618b-8ea5-410e-ad95-401195d7f027 at position 6 of 12 in additional filter chain; firing Filter: 'OAuth2ClientAuthenticationProcessingFilter'
2019-04-10 14:25:42.984 DEBUG 65661 --- [nio-5050-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/callback'; against '/callback'
2019-04-10 14:25:42.984 DEBUG 65661 --- [nio-5050-exec-3] uth2ClientAuthenticationProcessingFilter : Request is to process authentication
2019-04-10 14:25:42.995 DEBUG 65661 --- [nio-5050-exec-3] g.c.AuthorizationCodeAccessTokenProvider : Retrieving token from http://localhost:9090/auth/realms/prototype/protocol/openid-connect/token
2019-04-10 14:25:43.001 DEBUG 65661 --- [nio-5050-exec-3] g.c.AuthorizationCodeAccessTokenProvider : Encoding and sending form: {grant_type=[authorization_code], code=[f1edb261-bca0-4034-a1cb-508e8516bf39.885cb558-b19c-4610-8db7-be0c3193e33f.e054618b-8ea5-410e-ad95-401195d7f027], redirect_uri=[http://localhost:5050/callback], client_id=[internal-backend], client_secret=[83de9dcf-f7a0-4336-9f8e-0230de51e5a6]}
2019-04-10 14:25:43.044 DEBUG 65661 --- [nio-5050-exec-3] o.s.s.oauth2.client.OAuth2RestTemplate   : HTTP GET http://localhost:9090/auth/realms/prototype/protocol/openid-connect/userinfo
2019-04-10 14:25:43.046 DEBUG 65661 --- [nio-5050-exec-3] o.s.s.oauth2.client.OAuth2RestTemplate   : Accept=[application/json, application/*+json]
2019-04-10 14:25:43.049 DEBUG 65661 --- [nio-5050-exec-3] o.s.s.oauth2.client.OAuth2RestTemplate   : Response 200 OK
2019-04-10 14:25:43.049 DEBUG 65661 --- [nio-5050-exec-3] o.s.s.oauth2.client.OAuth2RestTemplate   : Reading to [java.util.Map<?, ?>]
2019-04-10 14:25:43.052 DEBUG 65661 --- [nio-5050-exec-3] uth2ClientAuthenticationProcessingFilter : Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.oauth2.provider.OAuth2Authentication@cf8a8ece: Principal: unknown; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=0:0:0:0:0:0:0:1, sessionId=<SESSION>, tokenType=bearertokenValue=<TOKEN>; Granted Authorities: ROLE_USER
2019-04-10 14:25:43.052 DEBUG 65661 --- [nio-5050-exec-3] RequestAwareAuthenticationSuccessHandler : Using default Url: /
2019-04-10 14:25:43.052 DEBUG 65661 --- [nio-5050-exec-3] o.s.s.web.DefaultRedirectStrategy        : Redirecting to '/'
...

如您所见,收到访问令牌后,将重定向到/而不是/api/user。如果我删除了@EnableResourceServer批注和ResourceServerConfigurerAdapter,则ExceptionTranslationFilter将请求保存在请求缓存中,并在获取访问令牌后使用正确的重定向。

这是我最小的代码示例:

@EnableOAuth2Client
@EnableResourceServer
@SpringBootApplication
public class ClientApplication {

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

    @Configuration
    public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        @Qualifier("oauth2ClientContext")
        private OAuth2ClientContext oauth2ClientContext;
        @Autowired
        private OAuth2ProtectedResourceDetails details;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/callback")).and()
                    .authorizeRequests()
                        .antMatchers("/user", "/callback").permitAll()
                        .anyRequest().authenticated()
                    .and().addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
        }

        public Filter ssoFilter() {
            OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter("/callback");
            OAuth2RestTemplate restTemplate = myRestTemplate();
            filter.setRestTemplate(restTemplate);
            UserInfoTokenServices tokenServices = new UserInfoTokenServices("http://localhost:9090/auth/realms/prototype/protocol/openid-connect/userinfo", restTemplate.getResource().getClientId());
            tokenServices.setRestTemplate(restTemplate);
            filter.setTokenServices(tokenServices);
            return filter;
        }

        @Bean
        public OAuth2RestTemplate myRestTemplate() {
            return new OAuth2RestTemplate(details, oauth2ClientContext);
        }
    }

    @Configuration
    public static class ResourceServerConfig extends ResourceServerConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .antMatcher("/api/**")
                    .authorizeRequests()
                        .anyRequest().authenticated();
        }
    }

    @RestController
    public static class ResourceController {
        @Autowired
        @Qualifier("myRestTemplate")
        OAuth2RestTemplate client;

        @GetMapping("/api/user")
        public String getUser() {
            String token = client.getAccessToken().getValue();
            String clientId = client.getResource().getClientId();
            return "Client " + clientId + " has obtained token\n" + token + " to request protected resource.";
        }
    }
}

我该如何解决?

0 个答案:

没有答案