복붙노트

[SPRING] 'OPTIONS / logout'요청이 'POST / logout'과 일치하지 않습니다.

SPRING

'OPTIONS / logout'요청이 'POST / logout'과 일치하지 않습니다.

나는이 GitHub 샘플에서 3 개의 상호 연결된 어플리케이션을 분해함으로써 Spring Cloud와 Spring OAuth2를 연구 중이다. authserver 응용 프로그램에서 / oauth / revoke-token 끝점을 열고 http : // localhost : 9999 / uaa / logout을 사용하여 ui 응용 프로그램에서 호출하면 authserver 응용 프로그램의 디버그 로그에 다음과 같은 오류 메시지가 나타납니다 로그 아웃 요청을 거부하는 중 :

Request 'OPTIONS /logout' doesn't match 'POST /logout

ui 앱이 hello.js의 로그 아웃 함수를 호출 할 때 전역 로그 아웃을 성공시키기 위해 샘플 GitHub 앱의 코드에 어떤 특별한 변경이 필요합니까?

초기 노력 :

지금까지 내가 한 변경 사항은 다음과 같습니다.

AuthserverApplication.java에 다음의 @Bean 정의를 추가하십시오.

@Bean
public TokenStore tokenStore() {return new InMemoryTokenStore();}

authserver 앱의 데모 패키지에 다음 컨트롤러 클래스를 추가합니다.

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

ui 앱에서 hello.js의 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

ui 앱이 모든 앱에서 사용자의 글로벌 로그 아웃을 시작하도록 GitHub 샘플 앱에서 변경해야하는 다른 특정 코드 변경 사항은 무엇입니까?

참고 : 분명히 / uaa / logout은 / oauth / revoke-token과 다른 URL입니다. 그러나 Spring Security와 OAuth의 내부 동작은이 OP에 대한 대답이 없으면 명확하지 않습니다.

@ StuXnet의 제안 :

요청에 대한 Firefox 개발자 도구 네트워크 탭의 내용은 다음과 같습니다.

OPTIONS 메소드로 http : // localhost : 9999 / uaa / login에 대한 요청이 거부되어 403 오류가 발생했습니다.

원시 요청 헤더는 다음과 같습니다.

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

원시 응답 헤더는 다음과 같습니다.

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의 다음 요청 헤더 :

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의 다음 응답 헤더와 함께 :

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는 OP 상단의 링크에서 원본 샘플 앱을 복제 한 다음 위의 내용을 변경하거나

2.)이 파일 공유 링크에서 OP의 모든 변경 사항을 포함하여 내 devbox에있는 압축 된 버전의 응용 프로그램을 다운로드 한 다음 :

2.a.) 응용 프로그램을 푸십시오.

2.b.) 터미널 창을 oauth2 / resource로 이동하고 mvn spring-boot : run을 실행하십시오. 그런 다음 두 번째 터미널 창을 oauth2 / authserver로 이동하고 mvn spring-boot :를 입력하십시오. 그런 다음 세 번째 터미널 창을 oauth2 / ui로 이동하고 mvn spring-boot :를 입력하십시오.

2.c.) 웹 브라우저에서 http : // localhost : 8080으로 이동 한 다음 login을 클릭 한 다음 사용자 이름과 암호로 password를 입력하십시오. 인증을 마친 후 로그 아웃 버튼을 클릭하면 403 오류가 재현됩니다. 브라우저의 개발자 도구의 네트워크 탭을 사용하여 브라우저 활동을 검사하십시오. authserver 응용 프로그램을 실행중인 터미널에서 Spring의 활동을 보려면 Spring Boot 로그를보십시오.

3.) 세 폴더를 기존 maven 프로젝트와 같이 eclipse (또는 다른 IDE)로 가져 오거나 텍스트 편집기로 코드 파일을 열어 편집을 다시 시작한 다음 2 단계에서 다시 테스트하십시오.

솔루션을 분리하는 데 도움을 줄 수있는 다른 방법은 무엇입니까?

해결법

  1. ==============================

    1.왜 이렇게하고 싶은지, 그리고 좋은 아이디어인지 아닌지에 대한 질문을 떠나서 JS 클라이언트가 다른 서버의 엔드 포인트로 POST 중이므로 CORS (Cross-Origin Resource Sharing)와 Cross Site Request Forgery (CSRF)는 Spring MVC와 Spring Security를 ​​사용하기 때문에 인증 서버에서 기본적으로 잠긴다.

    왜 이렇게하고 싶은지, 그리고 좋은 아이디어인지 아닌지에 대한 질문을 떠나서 JS 클라이언트가 다른 서버의 엔드 포인트로 POST 중이므로 CORS (Cross-Origin Resource Sharing)와 Cross Site Request Forgery (CSRF)는 Spring MVC와 Spring Security를 ​​사용하기 때문에 인증 서버에서 기본적으로 잠긴다.

    CORS 문제는 여러 가지 방법으로 해결할 수 있습니다. 접근 방식은 요청 일치자를 사용하여 보안 구성을 통과하는 구멍을 펀치하는 방식 인 permitAll ()입니다. HttpSecurity.cors ()를 사용하여 Spring MVC와 Spring Security를 ​​훨씬 잘 통합했다. 사용자 가이드 링크 : http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors. 튜토리얼 (vanilla 리소스 서버)의 간단한 예 :

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors()
            ...;
    }
    

    이것은 @CrossOrigin으로 MVC 선언 된 끝점과의 통합을 전환합니다. 실제로 POST하려고하는 엔드 포인트는 여러분이 작성한 것이 아니며 Spring MVC 엔드 포인트가 아니기 때문에 cors (). configurationSource (...)를 대신 사용해야 할 수도있다.

    CSRF 문제는 다양한 방법으로 해결하기 쉽습니다. 시작한 튜토리얼에는 앵귤러 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());
    }
    
  2. from https://stackoverflow.com/questions/36705874/request-options-logout-doesnt-match-post-logout by cc-by-sa and MIT license