我正在尝试使用Spring Security OAuth2和JWT实现单点登录 . 我使用两个单独的应用程序

授权服务器 - 这是中央身份验证机制

客户端应用程序:使用SSO的应用程序

当用户尝试访问客户端应用程序中的安全页面时,他们将通过身份验证服务器重定向到首先进行身份验证 .

我正在使用OAuth2中的授权代码授权类型来驱动身份验证委派 .

Authorization server:

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

  public static final Logger LOGGER = LoggerFactory.getLogger(AuthorizationServerConfigurerAdapter.class);


  @Autowired
  private AuthenticationManager authenticationManager;


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

  @Bean
  public JwtAccessTokenConverter accessTokenConverter() {
      JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
      converter.setSigningKey("abcd");
      return converter;
  }

  @Bean
  @Primary
  public DefaultTokenServices tokenServices() {
      DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
      defaultTokenServices.setTokenStore(tokenStore());
      defaultTokenServices.setSupportRefreshToken(true);
      defaultTokenServices.setTokenEnhancer(accessTokenConverter());
      return defaultTokenServices;
  }

  @Override
  public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception {
    clientDetailsServiceConfigurer
    .inMemory()
        .withClient("webapp")
        .secret("Pass")
        .authorizedGrantTypes("implicit", "refresh_token", "password", "authorization_code")
        .scopes("user_info")
        .autoApprove(true);
  }

  @Override
  public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {    
    oauthServer.tokenKeyAccess("permitAll()")
    .checkTokenAccess("isAuthenticated()");
  }


  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
      endpoints
              .authenticationManager(authenticationManager);
  }

}

授权服务器上的安全配置

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter  {

  @Value("${ldap.url}")
  private String ldapUrl;

  @Value("${ldap.userDnPatterns}")
  private String ldapUserDnPatterns;

  @Autowired
  private PersonService personService;

  @Autowired
  private RoleService roleService;

  @Override
  protected void configure(HttpSecurity http) throws Exception { // @formatter:off
      http.requestMatchers()
          .antMatchers("/login", "/oauth/authorize")
          .and()
          .authorizeRequests()
          .anyRequest()
          .authenticated()
          .and()
          .formLogin()
          .permitAll();
  } // @formatter:on


  @Bean(name = "authenticationManager")
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
     .authenticationProvider(this.ldapAndDatabaseAuthenticationProvider());
  }

  @Bean(name="ldapAuthenticationProvider")
  public AuthenticationProvider ldapAndDatabaseAuthenticationProvider(){
    LdapUserDetailsMapper userDetailsMapper = new LdapUserDetailsMapper();
    userDetailsMapper.setRoleAttributes(new String[]{"groupMembership"});

    LdapAndDatabaseAuthenticationProvider provider = 
        new LdapAndDatabaseAuthenticationProvider(
            this.ldapAuthenticator(), 
            this.ldapAuthoritiesPopulator(),
            this.personService);
    provider.setUserDetailsContextMapper(userDetailsMapper);

    return provider;
  }

  @Bean( name = "ldapAuthoritiesPopulator" )
  public LdapAndDatabaseAuthoritiesPopulator ldapAuthoritiesPopulator(){
    return new LdapAndDatabaseAuthoritiesPopulator(this.contextSource(), "", roleService);
  }

  @Bean( name = "ldapAuthenticator" )
  public LdapAuthenticator ldapAuthenticator() {

      BindAuthenticator authenticator = new BindAuthenticator( this.contextSource() );
      authenticator.setUserDnPatterns(new String[]{"cn={0},ou=prod,o=TEMP"});

      return authenticator;
  }

  @Bean( name = "contextSource" )
  public DefaultSpringSecurityContextSource contextSource() {

      DefaultSpringSecurityContextSource contextSource =
              new DefaultSpringSecurityContextSource( ldapUrl );
      return contextSource;
  }


}

application.properties:

server.port=8888
server.context-path=/auth
security.basic.enabled=false

当我登录客户端应用程序时,它正确转发到授权服务器进行单点登录 . 我输入用户凭据 . 用户成功通过身份验证,但我在浏览器上看到以下错误:

OAuth错误错误=“invalid_grant”,error_description =“redirect_uri只能由implicit或authorization_code授权类型使用 . ”

网址显示:http://localhost:8888/auth/oauth/authorize?client_id=webapp&redirect_uri=http://localhost:8080/jwt/webapp&response_type=code&state=LGvAzj

我还在日志中看到以下内容:

02:14:43.610 [http-nio-8888-exec-6] DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping/getHandlerInternal Looking up handler method for path /oauth/authorize 
02:14:43.614 [http-nio-8888-exec-6] DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping/getHandlerInternal Returning handler method [public org.springframework.web.servlet.ModelAndView  org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map<java.lang.String, java.lang.Object>,java.util.Map<java.lang.String, java.lang.Str ing>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)] 
02:14:43.849 [http-nio-8888-exec-6] INFO  o.s.s.o.p.e.AuthorizationEndpoint/handleOAuth2Exception Handling OAuth2 error: error="invalid_grant", error_description="A redirect_uri can only be used by implicit or authorization_code grant types."

你能帮我找到问题吗?

UPDATE 实际上,杜尔是对的 . 这种配置是正确的,并且工作正常 . 我有另一个配置文件来配置JdbcClientDetails,它覆盖了在此配置中使用inmemory创建的clientDetailsService .