Spring Security 请求令牌时Spring授权服务器重定向到登录页面

erhoui1w  于 2023-02-23  发布在  Spring
关注(0)|答案(1)|浏览(194)

我们目前有两个Web应用程序通过CAS进行身份验证。它们之间的通信通过基本身份验证完成。

出于安全原因,我们希望切换到OAuth2以去除基本身份验证。同时,我们希望去除CAS,因为它不满足我们的要求。
所以我们的目标是这样的:

我现在可以登录到用户管理并操作数据。第二个应用程序也正确地将我重定向到第一个应用程序以对我进行身份验证。身份验证也正常工作。第一个应用程序正确地响应第二个应用程序。然后第二个应用程序对URL“oauth2/token”执行预期的POST。但第一个应用程序对“/login”回复302而不是令牌。
我遗漏了哪一点,还是仍需配置?
我已将自己定位于以下文档:https://docs.spring.io/spring-authorization-server/docs/current/reference/html/getting-started.html
我的授权服务器配置如下所示:

@Configuration
public class AuthorizationServerConfig {

  private final SecurityApp app;

  public AuthorizationServerConfig(SecurityApp app) {
    this.app = app;
  }

  @Bean
  @Order(1)
  public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)
      throws Exception {

    OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
        new OAuth2AuthorizationServerConfigurer();
    authorizationServerConfigurer
        .authorizationEndpoint(authorizationEndpoint ->
            authorizationEndpoint.consentPage("/oauth2/authorize"))
        .oidc(Customizer.withDefaults());   // Enable OpenID Connect 1.0

    RequestMatcher endpointsMatcher = authorizationServerConfigurer
        .getEndpointsMatcher();

    http
        .securityMatcher(endpointsMatcher)
        .authorizeHttpRequests(authorize ->
            authorize.anyRequest().authenticated()
        )
        .csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
        .exceptionHandling(exceptions ->
            exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
        )
        .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
        .apply(authorizationServerConfigurer);
    return http.build();
  }

  @Bean
  @Order(2)
  public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
      throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest().authenticated()
        )
        // Form login handles the redirect to the login page from the
        // authorization server filter chain
        .formLogin(Customizer.withDefaults());

    return http.build();
  }

  @Bean
  UserDetailsService users() {
    return app::findUserByLogin;
  }

  // OVERWATCH

  @Bean
  public RegisteredClientRepository registeredClientRepository() {

    return new RegisteredClientRepository() {
      @Override
      public void save(RegisteredClient registeredClient) {
        throw new NotImplementedException();
      }

      @Override
      public RegisteredClient findById(String id) {
        return app.findByClientId(id);
      }

      @Override
      public RegisteredClient findByClientId(String clientId) {
        return app.findByClientId(clientId);
      }
    };
  }

  @Bean
  public JWKSource<SecurityContext> jwkSource() {
    RSAPublicKey publicKey = app.getPublicKey();
    RSAPrivateKey privateKey = (RSAPrivateKey) app.getPrivateKey();
    RSAKey rsaKey = new RSAKey.Builder(publicKey)
        .privateKey(privateKey)
        .keyID(UUID.randomUUID().toString())
        .build();
    JWKSet jwkSet = new JWKSet(rsaKey);
    return new ImmutableJWKSet<>(jwkSet);
  }

  @Bean
  public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
    return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
  }

  @Bean
  public AuthorizationServerSettings authorizationServerSettings() {
    return AuthorizationServerSettings.builder().build();
  }

  // region Password Authenticator

  @Bean
  public PasswordEncoder passwordEncoder() {
    return app.passwordEncoder();
  }

  // endregion
}

应用程序2的配置如下所示:

@Configuration
@EnableWebSecurity
public class AceSecurityConfiguration extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
        .antMatcher("/**")
        .authorizeRequests()
        .antMatchers("/oauth/authorize**", "/login**", "/error**")
        .permitAll()
        .and()
        .authorizeRequests()
        .anyRequest().authenticated()
        .and()
        .oauth2Login( oauth2Login -> oauth2Login.defaultSuccessUrl("/index.html") );
  }
}

application.properties App 2的www.example.com是:

spring.security.oauth2.client.registration.<provider-name>.client-id=${app.uuid}
spring.security.oauth2.client.registration.<provider-name>.client-secret=${app.secret}
spring.security.oauth2.client.registration.<provider-name>.scope=openid
spring.security.oauth2.client.registration.<provider-name>.redirect-uri=http://127.0.0.1:8088/login/oauth2/code/<provider-name>
spring.security.oauth2.client.registration.<provider-name>.client-name=${app.name}
spring.security.oauth2.client.registration.<provider-name>.provider=${provider.name}
spring.security.oauth2.client.registration.<provider-name>.client-authentication-method=code
spring.security.oauth2.client.registration.<provider-name>.authorization-grant type=authorization_code

spring.security.oauth2.client.provider.<provider-name>.authorization-uri=http://localhost:8086/oauth2/authorize
spring.security.oauth2.client.provider.<provider-name>.token-uri=http://localhost:8086/oauth2/token
spring.security.oauth2.client.provider.<provider-name>.user-info-uri=http://localhost:8086/oauth2/userinfo?schema=openid
spring.security.oauth2.client.provider.<provider-name>.user-name-attribute=name
spring.security.oauth2.client.provider.<provider-name>.user-info-authentication-method=header
spring.security.oauth2.client.provider.<provider-name>.jwk-set-uri=http://localhost:8086/jwks

导致重定向的从App 2到App 1的请求为:

POST http://localhost:8086/oauth2/token

Body:
grant_type=authorization_code, 
code=Zls0ppjnS_RXyMVPB8fg_eQQgoiUAxRguOMsdyVYQpgd8eDkUDzgz813L0ybovTL7sNj0TDRUHibPfek9NzwULND1mty5WPW2DOtQjTAaEROL3qP7RvyTWXTEzzYe-o,
redirect_uri=[http://127.0.0.1:8088/login/oauth2/code/<provider-name>],
client_id=<app.uuid>

Header:
Accept:"application/json;charset=UTF-8", 
Content-Type:"application/x-www-form-urlencoded;charset=UTF-8"
wkftcu5l

wkftcu5l1#

对于遇到相同或类似问题的人来说。实际问题是:

spring.security.oauth2.client.registration.<provider-name>.client-authentication-method=code.

数据库中声明了其他身份验证方法。
另一个问题是PasswordEncoder的声明,数据库中的密码是以BCrypt加密的方式存储的,而共享密钥是以未加密的方式存储在数据库中的(以便能够在前端显示),因此比较这两个密钥时会出现问题。

相关问题