无法使 EnableOauth2Sso 正常工作——BadCredentialsException:无法获取访问令牌

Unable to get EnableOauth2Sso Working -- BadCredentialsException: Could not obtain access token

我正在尝试让一个简单的 Spring OAuth2 SSO 应用程序正常工作,但我一直无法这样做。以下是发生的步骤和结果:

  1. 命中由 OAuth2
  2. 保护的端点 /user
  3. 我被转发到一个简单的 Spring OAuth2 授权服务器
  4. 我向授权服务器进行身份验证
  5. 我同意访问
  6. 然后我在 OAuth2 SSO 应用程序上得到一个带有以下内容的白标签错误页面:

    Whitelabel Error Page
    
    This application has no explicit mapping for /error, so you are seeing this as a fallback.
    
    Mon Jul 13 08:19:18 EDT 2015
    There was an unexpected error (type=Unauthorized, status=401).
    Authentication Failed: Could not obtain access token
    

授权码在URL中。下面是示例 URL:

http://localhost:8083/login?code=9s63rU&state=Fo9S2M

我没有看到 HTTP POST 到授权服务器 /oauth/token 端点以获取 JWT。我通过授权服务器上的 /trace 端点验证了这一点。

异常堆栈为:

2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/css/**'
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/js/**'
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/images/**'
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/**/favicon.ico'
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/error'
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/health']
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/health'
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/health/**']
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/health/**'
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/health.*']
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/health.*'
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/info']
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/info'
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/info/**']
2015-07-13 08:23:32.695 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/info/**'
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/info.*']
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/info.*'
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/restart']
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/restart'
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/restart/**']
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/restart/**'
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/restart.*']
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/restart.*'
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/env']
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/env'
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/env/**']
2015-07-13 08:23:32.696 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/env/**'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/env.*']
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/env.*'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/refresh']
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/refresh'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/refresh/**']
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/refresh/**'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/refresh.*']
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/refresh.*'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/metrics']
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/metrics'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/metrics/**']
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/metrics/**'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/metrics.*']
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/metrics.*'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/pause']
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/pause'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/pause/**']
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/pause/**'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/pause.*']
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/pause.*'
2015-07-13 08:23:32.699 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/resume']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/resume'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/resume/**']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/resume/**'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/resume.*']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/resume.*'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/dump']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/dump'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/dump/**']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/dump/**'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/dump.*']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/dump.*'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/configprops']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/configprops'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/configprops/**']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/configprops/**'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/configprops.*']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/configprops.*'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/trace']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/trace'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/trace/**']
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/trace/**'
2015-07-13 08:23:32.700 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/trace.*']
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/trace.*'
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/beans']
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/beans'
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/beans/**']
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/beans/**'
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/beans.*']
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/beans.*'
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/mappings']
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/mappings'
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/mappings/**']
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/mappings/**'
2015-07-13 08:23:32.701 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/mappings.*']
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/mappings.*'
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/autoconfig']
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/autoconfig'
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/autoconfig/**']
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/autoconfig/**'
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/autoconfig.*']
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/autoconfig.*'
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.web.util.matcher.OrRequestMatcher  : No matches found
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request '/login' matched by universal pattern '/**'
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.security.web.FilterChainProxy        : /login?code=9s63rU&state=Fo9S2M at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.security.web.FilterChainProxy        : /login?code=9s63rU&state=Fo9S2M at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] o.s.security.web.FilterChainProxy        : /login?code=9s63rU&state=Fo9S2M at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2015-07-13 08:23:32.702 DEBUG 3516 --- [nio-8083-exec-7] 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@59b4132c
2015-07-13 08:23:32.703 DEBUG 3516 --- [nio-8083-exec-7] o.s.security.web.FilterChainProxy        : /login?code=9s63rU&state=Fo9S2M at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2015-07-13 08:23:32.703 DEBUG 3516 --- [nio-8083-exec-7] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/logout'
2015-07-13 08:23:32.703 DEBUG 3516 --- [nio-8083-exec-7] o.s.security.web.FilterChainProxy        : /login?code=9s63rU&state=Fo9S2M at position 5 of 11 in additional filter chain; firing Filter: 'OAuth2ClientAuthenticationProcessingFilter'
2015-07-13 08:23:32.703 DEBUG 3516 --- [nio-8083-exec-7] uth2ClientAuthenticationProcessingFilter : Request is to process authentication
2015-07-13 08:23:32.704 DEBUG 3516 --- [nio-8083-exec-7] uth2ClientAuthenticationProcessingFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Could not obtain access token
2015-07-13 08:23:32.705 DEBUG 3516 --- [nio-8083-exec-7] uth2ClientAuthenticationProcessingFilter : Updated SecurityContextHolder to contain null Authentication
2015-07-13 08:23:32.705 DEBUG 3516 --- [nio-8083-exec-7] uth2ClientAuthenticationProcessingFilter : Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@6a650b1c
2015-07-13 08:23:32.705 DEBUG 3516 --- [nio-8083-exec-7] .a.SimpleUrlAuthenticationFailureHandler : No failure URL set, sending 401 Unauthorized error
2015-07-13 08:23:32.705 DEBUG 3516 --- [nio-8083-exec-7] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2015-07-13 08:23:32.705 DEBUG 3516 --- [nio-8083-exec-7] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

我的示例 OAuth2 SSO 应用程序:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.security.oauth2.sso.EnableOAuth2Sso;
import org.springframework.cloud.security.oauth2.sso.OAuth2SsoConfigurerAdapter;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;

@SpringBootApplication
public class OAuth2ClientApplication {

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

    @RestController
    public static class SecuredController {
        @RequestMapping("/user")
        public Principal user(Principal user) {
            return user;
        }
    }

    @Configuration
    @EnableOAuth2Sso
    public static class OAuthSsoConfig extends OAuth2SsoConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.logout()
                    .and().antMatcher("/**")
                    .authorizeRequests()
                    .antMatchers("/index.html", "/home.html", "/", "/login").permitAll()
                    .anyRequest()
                    .authenticated()
                    .and().csrf().disable();
        }
    }
}

POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>test</groupId>
    <artifactId>oauth2-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>OAuth2 Client</name>
    <description>OAuth2 Client POC</description>

    <parent>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-parent</artifactId>
        <version>Angel.SR3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

我的 application.properties 文件:

server.port=8083
security.basic.enabled=false
spring.oauth2.client.accessTokenUri=http://localhost:8081/oauth/token
spring.oauth2.client.userAuthorizationUri=http://localhost:8081/oauth/authorize
spring.oauth2.client.clientId=oauth2Client
spring.oauth2.client.clientSecret=oauth2ClientSecret

spring.oauth2.resource.jwt.keyUri=http://localhost:8081/oauth/token_key

logging.level.org.springframework.security=DEBUG

如果您需要授权服务器的代码,请告诉我。

:: 更新 1::

我开始对此进行调试,然后发现抛出的实际异常是 InvalidRequestException,消息为:AuthorizationCodeAccessTokenProviderline 244 上的 Possible CSRF detected - state parameter was present but no state could be found

我尝试将 Oauth2SsoConfigurerAdapter 修改为此,但我仍然遇到相同的异常:

@Configuration
protected static class SecurityConfiguration extends OAuth2SsoConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.logout().and().antMatcher("/**").authorizeRequests()
                .antMatchers("/index.html", "/home.html", "/", "/login").permitAll()
                .anyRequest().authenticated().and().csrf()
                .csrfTokenRepository(csrfTokenRepository()).and()
                .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
    }

    private Filter csrfHeaderFilter() {
        return new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request,
                                            HttpServletResponse response, FilterChain filterChain)
                    throws ServletException, IOException {
                CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
                        .getName());
                if (csrf != null) {
                    Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                    String token = csrf.getToken();
                    if (cookie == null || token != null
                            && !token.equals(cookie.getValue())) {
                        cookie = new Cookie("XSRF-TOKEN", token);
                        cookie.setPath("/");
                        response.addCookie(cookie);
                    }
                }
                filterChain.doFilter(request, response);
            }
        };
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }
}

:: 更新 2::

InvalidRequestException 被抛出,因为 DefaultAccessTokenRequestpreservedState 返回 null(参见 AuthorizationCodeAccessTokenProviderline 239)。

preservedStateline 212Oauth2RestTemplate 中的 DefaultAccessTokenRequest 上设置,我确定 DefaultOauth2ClientContext 地图为空并返回 null.

接下来我将尝试验证 DefaultOAuth2ClientContext 中的 setPreserveState 调用。

:: 更新 3::

我更新了我的客户端配置以使用 Github 而不是我自己的 Spring OAuth2 授权服务器并且它有效。对我来说,这表明我的授权服务器配置可能存在问题。

我会尝试在我的 OAuth 服务器上进行一些调试,看看我是否能找出问题所在。

:: 更新 4::

成功!我是运行 OAuth2 授权和客户端服务器在同一台主机上,但端口不同。当我将客户端的上下文路径设置为根目录以外的路径时,一切都开始工作了。

我怀疑这与 JSESSIONID 和 cookies 有关。任何人都可以 link 我向文档解释这是如何工作的以供将来参考吗?

谢谢!

正在创建客户端应用程序: 如果您是 运行 本地主机上的客户端和身份验证服务器,则上下文路径必须是明确的,否则 cookie 路径会发生冲突,并且两个应用程序无法就会话标识符达成一致。

来源:https://spring.io/guides/tutorials/spring-boot-oauth2/#_social_login_authserver

Centinul,您已经发现这是由于 cookie 冲突造成的,不幸的是 cookie 不考虑端口号。因此两个应用程序相互干扰,因为它们都设置 JSESSIONID.

有两个简单的解决方法:

  1. 使用server.context-path将每个App移动到不同的路径,注意你需要为两个都这样做
  2. 将一个应用程序的 server.session.cookie.name 设置为不同的值,例如 APPSESSIONID

我建议将此解决方法放在您仅为本地主机激活的配置文件中。