Spring Security 5 OAuth2使用JWT Bearer授权类型遇401错误求助
我近期尝试在Spring Security 5 OAuth2中使用urn:ietf:params:oauth:grant-type:jwt-bearer授权类型,但调用http://127.0.0.1:8081/postArticles时返回401 Unauthorized错误,希望排查原因并解决。我搭建了三个项目:授权服务器(spring-security-oauth2-authorization_server,端口8080)、资源服务器(spring-security-oauth2-resource_server,端口8081)、客户端(spring-security-oauth2-client,端口8082),相关代码片段如下:
1. spring-security-oauth2-client
ArticlesController.java
@GetMapping(value = "/postArticles") public String postArticles( @RegisteredOAuth2AuthorizedClient("articles-client-jwt-bearer") OAuth2AuthorizedClient authorizedClient ,HttpServletRequest request ,HttpServletResponse response ) { return webClient .post() .uri("http://127.0.0.1:8081/postArticles") .attributes(oauth2AuthorizedClient(authorizedClient)) .bodyValue("new articles" + new Date()) .retrieve() .bodyToMono(String.class) .block(); }
WebClientConfig.java
@Bean(name = "wc") WebClient webClient( OAuth2AuthorizedClientManager authorizedClientManager) { ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = new ServletOAuth2AuthorizedClientExchangeFilterFunction( authorizedClientManager); return WebClient.builder().apply(oauth2Client.oauth2Configuration()).build(); } @Bean OAuth2AuthorizedClientManager authorizedClientManager(ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientRepository authorizedClientRepository) { OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder() .authorizationCode() .refreshToken() .clientCredentials() .provider(new JwtBearerOAuth2AuthorizedClientProvider()) .build(); DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager( clientRegistrationRepository, authorizedClientRepository); authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); return authorizedClientManager; }
SecurityConfig.java
@Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // .authorizeRequests(authorizeRequests -> // authorizeRequests.anyRequest().authenticated() // ) .headers().frameOptions().sameOrigin() //for h2 .and() .csrf().ignoringAntMatchers("/h2-console/**") .and() .oauth2Client(withDefaults()) ; return http.build(); }
application-oauth2.properties
spring.security.oauth2.client.registration.articles-client-jwt-bearer.provider: spring spring.security.oauth2.client.registration.articles-client-jwt-bearer.client-id: articles-client spring.security.oauth2.client.registration.articles-client-jwt-bearer.client-secret: secret spring.security.oauth2.client.registration.articles-client-jwt-bearer.authorization-grant-type: urn:ietf:params:oauth:grant-type:jwt-bearer spring.security.oauth2.client.registration.articles-client-jwt-bearer.scope: articles.read,articles.write spring.security.oauth2.client.registration.articles-client-jwt-bearer.client-name: articles-client-jwt-bearer spring.security.oauth2.client.provider.spring.issuer-uri: http://auth-server:8080
2. spring-security-oauth2-authorization_server
AuthorizationServerConfig.java
@Configuration(proxyBeanMethods = false) public class AuthorizationServerConfig { /** * A Spring Security filter chain for the Protocol Endpoints. * * @param http * @return * @throws Exception */ @Bean @Order(Ordered.HIGHEST_PRECEDENCE) 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 .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))) .oauth2ResourceServer().jwt() .and().and() ; return http.build(); } /** * An instance of RegisteredClientRepository for managing clients. Registered * information. * * @return */ @Bean public RegisteredClientRepository registeredClientRepository(JdbcOperations jdbcOperations) { RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString()) .clientId("articles-client") .clientSecret("{noop}secret") // .clientName("client1") .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) .authorizationGrantType(AuthorizationGrantType.JWT_BEARER) .redirectUri("http://127.0.0.1:8080/login/oauth2/code/articles-client-oidc") .redirectUri("http://127.0.0.1:8080/authorized") .scope(OidcScopes.OPENID) .scope(OidcScopes.PROFILE) .scope("articles.read") .scope("articles.write") .tokenSettings(TokenSettings.builder().accessTokenTimeToLive(Duration.ofDays(2)) .refreshTokenTimeToLive(Duration.ofDays(3)).build()) .clientSettings(ClientSettings.builder().requireAuthorizationConsent(false) .build()) .build(); return new InMemoryRegisteredClientRepository(registeredClient); } @Bean public OAuth2AuthorizationService authorizationService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { return new InMemoryOAuth2AuthorizationService(); } @Bean public OAuth2AuthorizationConsentService authorizationConsentService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { return new InMemoryOAuth2AuthorizationConsentService(); } /** * An instance of com.nimbusds.jose.jwk.source.JWKSource for signing access * tokens. * * @return */ @Bean public JWKSource<SecurityContext> jwkSource() { KeyPair keyPair = generateRsaKey(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); RSAKey rsaKey = new RSAKey.Builder(publicKey).privateKey(privateKey).keyID(UUID.randomUUID().toString()) .build(); JWKSet jwkSet = new JWKSet(rsaKey); return new ImmutableJWKSet<>(jwkSet); } /** * An instance of java.security.KeyPair with keys generated on startup used to * create the JWKSource above. * * @return */ private static KeyPair generateRsaKey() { KeyPair keyPair; try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); keyPair = keyPairGenerator.generateKeyPair(); } catch (Exception ex) { throw new IllegalStateException(ex); } return keyPair; } /** * An instance of ProviderSettings to configure Spring Authorization Server. * * @return */ @Bean public ProviderSettings providerSettings() { return ProviderSettings.builder().issuer("http://auth-server:8080").build(); } @Bean public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) { return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource); } }
3. spring-security-oauth2-resource_server
ResourceServerConfig.java
@Bean @Order(2) public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorize -> authorize .mvcMatchers(HttpMethod.POST, "/postArticles").hasAuthority("SCOPE_articles.write") .anyRequest().authenticated() ) .csrf().disable() .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt) ; return http.build(); }
ResourceController.java
@ResponseStatus(HttpStatus.CREATED) @PostMapping("/postArticles") public String postArticles(@RequestBody String newArticle) { return newArticle; }
application-oauth2.properties
spring.security.oauth2.resourceserver.jwt.issuer-uri: http://auth-server:8080
内容的提问来源于stack exchange,提问作者wae
相关产品推荐
相关产品推荐

