如果我在春季启动应用程序中添加注释@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.";
}
}
}
我该如何解决?