Spring授权服务器在授予同意后返回access_denied

问题描述 投票:0回答:1

我尝试设置一个非常小的 Spring 授权服务器示例,作为评估它在我的一个项目中使用的一部分。授权服务器将与 SPA 应用程序一起使用,因此将使用带有 PKCE 的授权代码流。我正在使用 Spring Boot 3.2.0。

示例应用程序由 Spring Initializr 生成,由单个配置文件组成,用于设置授权服务器的最低要求,该服务器很大程度上遵循官方文档中的 “操作方法”

@SpringBootApplication
@EnableWebSecurity
public class DemoApplication
{
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public UserDetailsService users() {
        UserDetails user = User.withDefaultPasswordEncoder()
                .username("admin")
                .password("admin")
                .roles("ADMIN")
                .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

        http
                // Redirect to the login page when not authenticated from the
                // authorization endpoint
                .exceptionHandling((exceptions) -> exceptions
                        .defaultAuthenticationEntryPointFor(
                                new LoginUrlAuthenticationEntryPoint("/login"),
                                new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
                        )
                );

        return http.cors(Customizer.withDefaults()).build();
    }

    @Bean
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity httpSecurity) throws Exception
    {
        return httpSecurity
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/admin/**").hasRole("ADMIN")
                        .requestMatchers("/", "/**").permitAll()
                )
                .cors(Customizer.withDefaults())
                .formLogin(Customizer.withDefaults())
                .build();
    }

    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient publicClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("public-client")
                .clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("http://127.0.0.1:4200")
                .clientSettings(ClientSettings.builder()
                        .requireAuthorizationConsent(true)
                        .requireProofKey(true)
                        .build()
                )
                .build();

        return new InMemoryRegisteredClientRepository(publicClient);
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource()
    {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.addAllowedOrigin("http://127.0.0.1:4200");
        config.setAllowCredentials(true);
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}

当向

/authorize
端点发出正确格式的请求时,我将按预期重定向到默认登录页面。

为了完整起见,将我重定向到此登录页面的示例请求看起来像

http://127.0.0.1:8080/oauth2/authorize?response_type=code&client_id=public-client&redirect_uri=http%3A%2F%2Flocalhost%3A4200&state=1234xyz&code_challenge=cFeDr-CjSa6l1C3w388Qoz1GpM3Pa0qzkOF9rq0Wp8A&code_challenge_method=S256
使用由 PKCE Tools

生成的代码质询和验证器

输入有效的用户凭据(如上面配置中的配置)时,我将按预期重定向到同意屏幕。

但是,在通过选择“提交同意”按钮授予同意后,我在重定向网址中收到“access_denied”错误。重定向到的 url 是

http://127.0.0.1:4200/?error=access_denied&error_description=OAuth%202.0%20Parameter%3A%20client_id&error_uri=https%3A%2F%2Fdatatracker.ietf.org%2Fdoc%2Fhtml%2Frfc6749%23section-4.1.2.1&state=1234xyz

这包括错误消息“access_denied”和错误描述“OAuth 2.0 Parameter: client_id”,并指出RFC的一个部分,其中不包含任何进一步有用的信息来解决此特定错误消息。

表面上,错误描述表明Spring认为client_id有问题,但我看不出它可能有什么问题。

我在这里遗漏了哪一块拼图,导致我在已成功通过身份验证并选择同意的有效用户收到此错误?

编辑2024-02-19

我在重新访问时注意到我对授权服务器的请求使用的是

127.0.0.1
,而我的重定向使用的是
localhost
。我已经纠正了这个问题,以便请求和重定向都使用相同的主机,并通过尝试
127.0.0.1
localhost
的主机对其进行了测试。但是,以一致的方式使用任一主机时的结果与原始问题中描述的相同,并且我仍然收到“access_denied”错误。

问题已更新以显示

127.0.0.1
的用法。

java spring spring-boot spring-security spring-authorization-server
1个回答
0
投票

我刚刚遇到了同样的问题,经过一番调查,发现需要在registeredClientRepository方法中添加额外的作用域(我之前只有作用域(OidcScopes.OPENID)),例如

@Bean
public RegisteredClientRepository registeredClientRepository() {
    RegisteredClient publicClient = RegisteredClient.withId(UUID.randomUUID().toString())
            .clientId("public-client")
            .clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
            .redirectUri("http://127.0.0.1:4200")
            .scope("your-scope")
            .scope(OidcScopes.OPENID)
            .clientSettings(ClientSettings.builder()
                    .requireAuthorizationConsent(true)
                    .requireProofKey(true)
                    .build()
            )
            .build();

然后将其添加到请求参数中,如下所示: http://127.0.0.1:8080/oauth2/authorize?response_type=code&client_id=public-client&redirect_uri=http%3A%2F%2Flocalhost%3A4200&state=1234xyz&code_challenge=cFeDr-CjSa6l1C3w388Qoz1GpM3Pa0qzkOF9rq0Wp8 A&code_challenge_method=S256&scope=您的范围

希望对你有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.