authorization_code 授权类型的 unsupported_grant_type 错误:Spring Security OAuth2

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

我正在尝试使用 Spring Security 和 OpenID Connect 来实现 OAuth2 授权服务器。 为此,我使用带有刷新令牌和 JWT 的授权代码流程。这是我的配置代码-

@Configuration public class SecurityConfig { @Bean @Order(1) public SecurityFilterChain asSecurityFilterChain(HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); http.getConfigurer(OAuth2AuthorizationServerConfigurer.class) .authorizationEndpoint( a -> a.authenticationProviders(getAuthorizationEndpointProviders())) .oidc(Customizer.withDefaults()); http.exceptionHandling( e -> e.authenticationEntryPoint( new LoginUrlAuthenticationEntryPoint("/login"))); return http.build(); } private Consumer<List<AuthenticationProvider>> getAuthorizationEndpointProviders() { return providers -> { for (AuthenticationProvider p : providers) { if (p instanceof OAuth2AuthorizationCodeRequestAuthenticationProvider x) { x.setAuthenticationValidator(new CustomRedirectUriValidator()); } } }; } @Bean @Order(2) public SecurityFilterChain appSecurityFilterChain(HttpSecurity http) throws Exception { http.formLogin() .and() .authorizeHttpRequests().anyRequest().authenticated(); return http.build(); } @Bean public UserDetailsService userDetailsService() { var u1 = User.withUsername("user") .password("password") .authorities("read") .build(); return new InMemoryUserDetailsManager(u1); } @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } @Bean public RegisteredClientRepository registeredClientRepository() { RegisteredClient r1 = RegisteredClient.withId(UUID.randomUUID().toString()) .clientId("client") .clientSecret("secret") .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .scope(OidcScopes.OPENID) .scope(OidcScopes.PROFILE) .redirectUri("https://springone.io/authorized") .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) .tokenSettings( TokenSettings.builder() .accessTokenFormat(OAuth2TokenFormat.REFERENCE) .accessTokenTimeToLive(Duration.ofSeconds(900)) .build()) .build(); return new InMemoryRegisteredClientRepository(r1); } @Bean public AuthorizationServerSettings authorizationServerSettings() { return AuthorizationServerSettings.builder() .build(); } @Bean public JWKSource<SecurityContext> jwkSource() throws Exception { KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA"); kg.initialize(2048); KeyPair kp = kg.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate(); RSAKey key = new RSAKey.Builder(publicKey) .privateKey(privateKey) .keyID(UUID.randomUUID().toString()) .build(); JWKSet set = new JWKSet(key); return new ImmutableJWKSet(set); } @Bean public OAuth2TokenCustomizer<JwtEncodingContext> oAuth2TokenCustomizer() { return context -> { context.getClaims().claim("test", "test"); }; } }

CustomRedirectUrlValidator

import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationContext; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationException; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationToken; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import java.util.function.Consumer; public class CustomRedirectUriValidator implements Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext> { @Override public void accept(OAuth2AuthorizationCodeRequestAuthenticationContext context) { OAuth2AuthorizationCodeRequestAuthenticationToken a = context.getAuthentication(); RegisteredClient registeredClient = context.getRegisteredClient(); String uri = a.getRedirectUri(); if (!registeredClient.getRedirectUris().contains(uri)) { var error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST); throw new OAuth2AuthorizationCodeRequestAuthenticationException(error, null); } } }

PKCE 代码验证器和代码质询生成为-

SecureRandom sr = new SecureRandom(); byte[] code = new byte[32]; sr.nextBytes(code); String codeVerifier = Base64.getUrlEncoder() .withoutPadding() .encodeToString(code); MessageDigest md; { try { md = MessageDigest.getInstance("SHA-256"); byte[] digested = md.digest(codeVerifier.getBytes()); String code_challenge = Base64.getUrlEncoder().withoutPadding().encodeToString(digested); log.info("Code verifier: {}", codeVerifier); log.info("Code challenge: {}", code_challenge); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } }
现在,这是我获取访问令牌所遵循的步骤-

  1. oauth2/authorize- 发出 GET 请求
http://localhost:8080/oauth2/authorize?response_type=code&client_id=client&scope=openid&redirect_uri=https://springone.io/authorized&code_challenge=z5f7uuzQ2f0c1CNpuY0UoQE5jSN30YpcxS2s6wmoPq0&code_challenge_method=S256

    提供登录用户名和密码为
  1. userpassword后,浏览器重定向到指定的重定向url-
https://springone.io/authorized?code=TfzC56cc7xwa0wS-O0VvMm1k6kOhYchOcj7sW_pXyeEaRIvw9V6N5YuXoeqwQka1Cvf0ZY9EzGg0dM9zlCXLPYU3q7_T9KVsuc1_sGTV7XBxChPxtq1VRoxuuORf g3Zx

    现在,使用提供的
  1. codePOST请求来获取访问令牌-
现在,如果一切正常,我必须能够在响应正文中获取令牌。但是,我却得到了错误-

{ "error_description": "OAuth 2.0 Parameter: grant_type", "error": "unsupported_grant_type", "error_uri": "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2" }
现在,我检查了 

Spring Security 授权类型Spring Security 授权服务器 授权类型 authorization_code 是否有效。但是,我不明白,为什么我会收到此错误? 请帮我解决这个问题。

spring-boot spring-security oauth-2.0 openid-connect spring-authorization-server
1个回答
0
投票
我刚刚遇到了同样的问题,但没有找到解决问题的方法。在获得访问令牌之前,我必须将 spring-boot 版本从 3.2.1 降级到 3.1.0。

插件{ id 'java' id 'org.springframework.boot' 版本 '3.1.0' id 'io.spring.dependency-management' 版本 '1.1.4' }

    创建对 oauth2/authorize-
  1. 的 GET 请求
http://localhost:9090/oauth2/authorize?response_type=code&client_id=client&scope=openid&redirect_uri=http://localhost:9090/redirect/authorized&code_challenge=OaWJmipPOKmE66leDkUVMs8V9Iy8l6gg0NBsRFzgAeg&code_challenge_method=S256

    在浏览器显示的默认登录表单上提供登录用户名和密码后,您将被重定向到指定的重定向网址-
http://localhost:9090/redirect/authorized?code=OspZOqTvauO59fLZm7Z7PFO10vzznxpH9TcIhaXIcVshOmI5f_O-oDv4zej7WBS8Jq_USUAm8BgkC-P0vk8mRXUhYTbIwrwmYN3C6hnjP4rNnpghf9MzlyIs 8KZGOFgX

    接下来,使用从授权服务器获取的代码来请求访问令牌,如下所示:
http://localhost:9090/oauth2/token?client_id=client&redirect_uri=http://localhost:9090/redirect/authorized&grant_type=authorization_code&code=OspZOqTvauO59fLZm7Z7PFO10vzznxpH9TcIhaXIcVshOmI5f_O-oDv4zej7WBS8Jq_USUAm8BgkC -P0vk8mRXUhYTbIwrwmYN3C6hnjP4rNnpghf9MzlyIs8KZGOFgX&code_verifier=oIoS6DKeU5B3Dccu_QOutW58En8Ycs5tuqk7hv7rY0A

enter image description here

enter image description here

enter image description here

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