请求 'OPTIONS /logout' 与 'POST /logout' 不匹配
Posted
技术标签:
【中文标题】请求 \'OPTIONS /logout\' 与 \'POST /logout\' 不匹配【英文标题】:Request 'OPTIONS /logout' doesn't match 'POST /logout请求 'OPTIONS /logout' 与 'POST /logout' 不匹配 【发布时间】:2016-08-10 21:26:05 【问题描述】:我正在通过分解the three interconnected apps in this GitHub sample来研究Spring Cloud和Spring OAuth2。当我在authserver
app 中打开/oauth/revoke-token
端点,然后使用http://localhost:9999/uaa/logout
从ui
app 调用它时,authserver
app 的调试日志在拒绝注销请求时会给出以下错误消息:
Request 'OPTIONS /logout' doesn't match 'POST /logout
ui
app从hello.js
调用注销函数时,需要对the sample GitHub apps中的代码进行哪些具体的更改才能使全局注销成功?
初步努力:
到目前为止我所做的更改包括:
将以下@Bean 定义添加到AuthserverApplication.java:
@Bean
public TokenStore tokenStore() return new InMemoryTokenStore();
在demo
package of the authserver
app中添加如下控制器类:
@Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter
@Autowired
TokenStore tokenStore;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
endpoints.tokenStore(tokenStore);
@RequestMapping(value = "/oauth/revoke-token", method = RequestMethod.GET)
@ResponseStatus(HttpStatus.OK)
public void logout(HttpServletRequest request)
String authHeader = request.getHeader("Authorization");
if (authHeader != null)
String tokenValue = authHeader.replace("Bearer", "").trim();
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
tokenStore.removeAccessToken(accessToken);
将hello.js
in the ui
app的logout()
方法改成如下:
self.logout = function()
$http.post('http://localhost:9999/uaa/logout', ).finally(function()
$rootScope.authenticated = false;
$location.path("/");
);
但当用户点击浏览器中的注销按钮并触发对http://localhost:9999/uaa/logout
的调用时,authserver
应用程序的调试日志会给出以下输出:
2016-04-18 15:34:07.142 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/css/**']
2016-04-18 15:34:07.142 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/css/**'
2016-04-18 15:34:07.142 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/js/**']
2016-04-18 15:34:07.142 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/js/**'
2016-04-18 15:34:07.142 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/images/**']
2016-04-18 15:34:07.142 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/images/**'
2016-04-18 15:34:07.142 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/**/favicon.ico']
2016-04-18 15:34:07.142 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/**/favicon.ico'
2016-04-18 15:34:07.142 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/error']
2016-04-18 15:34:07.142 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/error'
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/login']
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/login'
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/oauth/authorize']
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/oauth/authorize'
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/oauth/confirm_access']
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/oauth/confirm_access'
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout']
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/logout'
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : matched
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] 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@5790c1b4
2016-04-18 15:34:07.143 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /logout' doesn't match 'POST /logout
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 6 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /logout' doesn't match 'POST /login
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /logout; Attributes: [authenticated]
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2016-04-18 15:34:07.144 DEBUG 313 --- [io-9999-exec-10] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@539015a, returned: -1
2016-04-18 15:34:07.145 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) ~[spring-security-core-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232) ~[spring-security-core-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:123) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114) ~[spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) [spring-security-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.5.RELEASE.jar:4.2.5.RELEASE]
...
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]
2016-04-18 15:34:07.146 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.util.matcher.AndRequestMatcher : Trying to match using Ant [pattern='/**', GET]
2016-04-18 15:34:07.146 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /logout' doesn't match 'GET /**
2016-04-18 15:34:07.146 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.util.matcher.AndRequestMatcher : Did not match
2016-04-18 15:34:07.146 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.s.HttpSessionRequestCache : Request not saved as configured RequestMatcher did not match
2016-04-18 15:34:07.146 DEBUG 313 --- [io-9999-exec-10] o.s.s.w.a.ExceptionTranslationFilter : Calling Authentication entry point.
2016-04-18 15:34:07.146 DEBUG 313 --- [io-9999-exec-10] o.s.s.web.DefaultRedirectStrategy : Redirecting to 'http://localhost:9999/uaa/login'
2016-04-18 15:34:07.147 DEBUG 313 --- [io-9999-exec-10] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2016-04-18 15:34:07.147 DEBUG 313 --- [io-9999-exec-10] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
the GitHub sample apps 中还需要更改哪些其他特定代码更改才能使ui
应用程序触发用户从所有应用程序全局注销?
注意:显然,/uaa/logout
与 /oauth/revoke-token
是不同的 URL。但是,如果没有对此 OP 的回答,Spring Security 和 OAuth 在这种情况下的内部工作原理并不清楚。
@StuXnet 的建议:
该请求的 Firefox 开发者工具网络选项卡的内容是:
使用方法OPTIONS
对http : // localhost:9999/uaa/login
的请求被拒绝并出现403
错误。
原始的request
标头是:
Host: localhost:9999
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://localhost:8080
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-requested-with
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
原始的response
标头是:
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 20
Date: Mon, 18 Apr 2016 23:45:46 GMT
Server: Apache-Coyote/1.1
X-Application-Context: application:9999
接下来,我把LoginConfig的config(http)方法改成如下:
@Override
protected void configure(HttpSecurity http) throws Exception
// @formatter:off
http
.formLogin().loginPage("/login").permitAll()
.and()
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access", "/logout", "/oauth/revoke-token")
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"/logout").permitAll()
.anyRequest().authenticated();
// @formatter:on
这导致 Spring Boot DEBUG 日志中的以下新打印输出:
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/css/**']
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/css/**'
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/js/**']
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/js/**'
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/images/**']
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/images/**'
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/**/favicon.ico']
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/**/favicon.ico'
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/error']
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/error'
2016-04-18 19:22:06.202 DEBUG 5319 --- [io-9999-exec-10] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2016-04-18 19:22:06.203 DEBUG 5319 --- [io-9999-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Request '/logout' matched by universal pattern '/**'
2016-04-18 19:22:06.203 DEBUG 5319 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /logout has an empty filter list
2016-04-18 19:22:06.204 DEBUG 5319 --- [io-9999-exec-10] .s.o.p.e.FrameworkEndpointHandlerMapping : Looking up handler method for path /logout
2016-04-18 19:22:06.205 DEBUG 5319 --- [io-9999-exec-10] .s.o.p.e.FrameworkEndpointHandlerMapping : Did not find handler method for [/logout]
以及 Firefox 中的以下 request
标头:
Host: localhost:9999
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://localhost:8080
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-requested-with
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
连同 Firefox 中的以下 response
标头:
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 20
Date: Tue, 19 Apr 2016 02:22:06 GMT
Server: Apache-Coyote/1.1
X-Application-Context: application:9999
然后我尝试将LoginConfig
的configure(http)
方法更改为:
@Override
protected void configure(HttpSecurity http) throws Exception
// @formatter:off
http
.formLogin().loginPage("/login").permitAll()
.and()
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access", "/logout", "/oauth/revoke-token")
.and()
.authorizeRequests()
.anyRequest().authenticated()
// @formatter:on
.and()
.csrf()
.ignoringAntMatchers("/logout");
但结果是 authserver
应用程序的以下 Spring Boot DEBUG 日志:
2016-04-19 10:12:13.545 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/css/**']
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/css/**'
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/js/**']
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/js/**'
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/images/**']
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/images/**'
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/**/favicon.ico']
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/**/favicon.ico'
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/error']
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/logout'; against '/error'
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request '/logout' matched by universal pattern '/**'
2016-04-19 10:12:13.546 DEBUG 4593 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy : /logout has an empty filter list
2016-04-19 10:12:13.547 DEBUG 4593 --- [nio-9999-exec-2] .s.o.p.e.FrameworkEndpointHandlerMapping : Looking up handler method for path /logout
2016-04-19 10:12:13.548 DEBUG 4593 --- [nio-9999-exec-2] .s.o.p.e.FrameworkEndpointHandlerMapping : Did not find handler method for [/logout]
在您的机器上重现问题:
要在您自己的机器上重现该问题,您可以:
1.) git clone OP 顶部链接处的原始示例应用程序,然后进行如上所示的更改,或者
2.) 下载the zipped version of the app as it exists on my devbox including all the changes from the OP at this file sharing link,然后:
2.a.) 解压应用程序。
2.b.) 将终端窗口导航到 oauth2/resource
和 mvn spring-boot:run
。然后将第二个终端窗口导航到oauth2/authserver
并键入mvn spring-boot:run
。然后将第三个终端窗口导航到oauth2/ui
并键入mvn spring-boot:run
。
2.c.) 将 Web 浏览器导航到 http : // localhost:8080
,然后单击 login
,然后输入 user
以获取 username
和 password
以获取 password
。通过身份验证后,单击logout
按钮重现 403 错误。使用浏览器开发工具的网络选项卡检查浏览器活动。在运行 authserver
应用程序的终端中查看 Spring Boot 日志以查看 Spring 的活动。
3.) 将这三个文件夹作为现有的 maven 项目导入到 eclipse(或另一个 IDE)中,或者使用文本编辑器打开代码文件进行编辑,然后在步骤 2 中重复重新启动和重新测试。
我还能提供什么来帮助隔离解决方案?
【问题讨论】:
@stuXnet 我刚刚添加了 Firefox 开发人员工具网络选项卡的输出。这是否有助于您隔离解决方案? @stuXnet 我刚刚将尝试您的请求的结果添加到我的 OP 末尾。似乎刚刚重新安排了安全过滤器,还没有解决问题.. @stuXnet 谢谢。请参阅 OP 的末尾,我在其中添加了尝试您的建议的结果。 @stuXnet 谢谢。我压缩了我的 devbox 上存在的应用程序,并将 tar 球上传到文件共享站点。我在 OP 的末尾添加了一个部分,以提供指向 tar 球的链接以及重现问题的说明。您也可以git clone
原始版本并进行 OP 中描述的更改。你愿意试试吗?
我会的,但我最早能看的是星期六。我将删除我的其他 cmets,因为您已经在 OP 中尝试并记录了它们 :)
【参考方案1】:
暂且不提你为什么要这样做以及这是否是个好主意的问题:你的 JS 客户端正在向另一台服务器上的端点进行 POST,因此你面临两个问题:跨域资源共享(CORS ) 和跨站点请求伪造 (CSRF),默认情况下这两者都在您的 Auth 服务器中被锁定,因为它使用 Spring MVC 和 Spring Security。
可以通过多种方式解决 CORS 问题,包括您采用的方法,即使用请求匹配器在安全配置中打一个洞 permitAll()
。使用 HttpSecurity.cors()
在 Spring MVC 和 Spring Security 之间有更好的集成。用户指南链接:http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors。教程中的简单示例(香草资源服务器):
@Override
protected void configure(HttpSecurity http) throws Exception
http.cors()
...;
这样做是打开与带有@CrossOrigin
的 MVC 声明端点的集成。实际上,您尝试 POST 的端点不是您编写的端点,也不是 Spring MVC 端点,因此您可能必须改用 cors().configurationSource(...)
。
CSRF 问题也很容易以各种不同的方式解决。您开始的教程有明确的示例显示如何为 Angular JS 执行此操作(但不在您正在使用的应用程序中,因为该教程不是关于从 SSO 提供程序注销)。在这种情况下,我们使用HttpSecurity.csrf()
功能。用户指南链接:http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf。 UI 应用中教程中的简单示例:
@Override
public void configure(HttpSecurity http) throws Exception
http
...
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
【讨论】:
以上是关于请求 'OPTIONS /logout' 与 'POST /logout' 不匹配的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security Logout 不适用于 Spring 4 CORS
当对 localhost:121/logout 进行 GET 请求时,我得到“accounts.views.logout 没有返回 HttpResponse 对象”。这是一个问题吗?