Spring Security 如何使用spring授权服务器1.0.0验证客户端应用程序?

7eumitmz  于 2022-12-13  发布在  Spring
关注(0)|答案(2)|浏览(189)

我正在尝试建立一个spring Boot 客户端应用程序,并通过spring授权服务器1.0.0进行身份验证。但是我无法登录到该应用程序。它总是重定向到spring授权服务器登录页面。任何人都请帮助我提供指导。我在下面描述我的应用程序配置:
授权服务器

port: 9000

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.0</version>
</parent>
<properties>
    <java.version>17</java.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mariadb.jdbc</groupId>
        <artifactId>mariadb-java-client</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
        <version>2.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-oauth2-authorization-server</artifactId>
        <version>1.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>5.0.1</version>
    </dependency>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>31.1-jre</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version>
    </dependency>
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>20041127.091804</version>
    </dependency>
    <dependency>
        <groupId>commons-beanutils</groupId>
        <artifactId>commons-beanutils</artifactId>
        <version>20030211.134440</version>
    </dependency>
</dependencies>

授权服务器配置

@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {
    private final PasswordEncoder passwordEncoder;

    public AuthorizationServerConfig(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(Customizer.withDefaults());   // Enable OpenID Connect 1.0

        // @formatter:off
        http
                .exceptionHandling(exceptions ->
                        exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
                )
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); // Accept access tokens for User Info and/or Client Registration
        // @formatter:on
        return http.build();
    }

    // @formatter:off
    @Bean
    public RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {

        // Save registered client in db as if in-memory
        JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
        RegisteredClient existingClient = registeredClientRepository.findByClientId("front-client");
        if(existingClient == null){
            RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
                    .clientId("front-client")
                    .clientSecret(passwordEncoder.encode("123456"))
                    .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                    .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                    .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                    //.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                    .redirectUri("http://127.0.0.1:8080/login/oauth2/code/front-client-oidc")
                    .redirectUri("http://127.0.0.1:8080/authorized")
                    .scope(OidcScopes.OPENID)
                    .scope("read")                    
                    .tokenSettings(TokenSettings.builder()
                            .accessTokenTimeToLive(Duration.ofDays(30))
                            .refreshTokenTimeToLive(Duration.ofDays(365))
                            .build())
                    //.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
                    .build();
            registeredClientRepository.save(registeredClient);
        }
        return registeredClientRepository;
    }
    // @formatter:on

    
    @Bean
    public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
        return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
    }

    @Bean
    public OAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
        return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);
    }

    @Bean
    public JWKSource<SecurityContext> jwkSource() {
        RSAKey rsaKey = Jwks.generateRsa();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
    }

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

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

授权服务器上的安全配置

@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class DefaultSecurityConfig {

    private final CustomAuthenticationProvider customAuthenticationProvider;

    public DefaultSecurityConfig(CustomAuthenticationProvider customAuthenticationProvider) {
        this.customAuthenticationProvider = customAuthenticationProvider;
    }

    // @formatter:off
    @Bean
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http    .csrf().disable()
                .authorizeHttpRequests(authorize ->
                        authorize.anyRequest().authenticated()
                )
                .formLogin(withDefaults()); //for default login page                
        return http.build();
    }
    // @formatter:on

    @Autowired
    public void bindAuthenticationProvider(AuthenticationManagerBuilder authenticationManagerBuilder){
        authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider);
    }
}

客户端应用程序配置

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>  
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity6</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>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

属性文件配置

server:
  port: 8080
spring:
  security:
    oauth2:
      client:
        registration:
          front-client-oidc:
            provider: spring
            client-id: front-client
            client-secret: 123456
            authorization-grant-type: authorization_code
            redirect-uri: "http://127.0.0.1:8080/login/oauth2/code/front-client-oidc"
            scope: openid
            client-name: front-client-oidc
          front-client-authorization-code:
            provider: spring
            client-id: front-client
            client-secret: 123456
            authorization-grant-type: authorization_code
            redirect-uri: "http://127.0.0.1:8080/authorized"
            scope: read
            client-name:  front-client-authorization-code
          front-client-client-credentials:
            provider: spring
            client-id: front-client
            client-secret: 123456
            authorization-grant-type: client_credentials
            scope: read,write
            client-name: front-client-client-credentials
        provider:
          spring:
            issuer-uri: http://127.0.0.1:9000

客户端应用程序上的安全配置

@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class SecurityConfig {

    // @formatter:off
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeHttpRequests(authorize ->
                authorize.anyRequest().authenticated()
            )
            .oauth2Login(oauth2Login ->
                oauth2Login.loginPage("/oauth2/authorization/front-client-oidc"))
            .oauth2Client(withDefaults());
        return http.build();
    }
    // @formatter:on
}

@Controller
public class DefaultController {
    @GetMapping("/")
    public String root() {
        return "redirect:/index";
    }

    @GetMapping("/index")
    public String index() {
        return "index";
    }
}

浏览器主控台

Request URL: http://localhost:8080

redirect to: http://127.0.0.1:9000/login

redirect to: http://127.0.0.1:9000/oauth2/authorize?response_type=code&client_id=front-client&scope=openid&state=SKhb4bxYHH36G9mRVb4Dx4b4MCzLk8J85FiSjnwQjTw=&redirect_uri=http://127.0.0.1:8080/login/oauth2/code/front-client-oidc&nonce=nmGlkPVUvvUFEE3_WhaiKonKcGqQQWUMbP__ABznb6A&continue

redirect to: http://127.0.0.1:8080/login/oauth2/code/front-client-oidc?code=yBikXvgTh3vVDztjLsHeFFzkN7xeskyo9dERmjG002d9Jnjwrw21PpzjzuttTZ4cfp5E4vj9FfqG23jObRFoiiPL3G1IHEIzXa2wf-l8f3iNEGBZ2GTXrSv_6ZxV3biJ&state=SKhb4bxYHH36G9mRVb4Dx4b4MCzLk8J85FiSjnwQjTw%3D

redirect to: http://127.0.0.1:8080/oauth2/authorization/front-client-oidc?error

again redirect to: http://127.0.0.1:9000/login
vmpqdwk3

vmpqdwk31#

您应该允许匿名访问loginoauth2(这两个都是要验证的用户所必需的):

http.authorizeHttpRequests()
    .requestMatchers("/login/**").permitAll()
    .requestMatchers("/oauth2/**").permitAll()
    .anyRequest().authenticated();

此外,我不知道确切的原因,但在某些时候,我必须强制登录页面和成功URL,因为spring-boot默认将我发送到授权服务器而不是客户端:

http.loginPage("%s://localhost:%d/oauth2/authorization/spring-addons-public".formatted(isSsl ? "https" : "http", serverProperties.getPort()) );
http.defaultSuccessUrl("%s://localhost:%d/swagger-ui/index.html".formatted(isSsl ? "https" : "http", serverProperties.getPort()), true);
kfgdxczn

kfgdxczn2#

它解决了,这是密码编码问题

相关问题