SpringBoot3集成Oauth2.1——3access_token使用
文章目录
- 尝试直接访问接口
- 增加资源配置
- 核心代码
- 完整代码
- 验证
在之前的篇幅中,我们介绍了oauth2.1的快速入门认证。现在开始我们要开始使用这个access_token了。
尝试直接访问接口
由于我们当前认证服务中,已经有了一些接口信息,现在,我们访问任意接口,如下所示,可以看到,访问这个接口,返回的是登录页面。
虽然我们知道,这个肯定访问不成功,但是,我们也得明白,页面返回的是登录页面,这明显也是不对到了,应该是返回401才对,因为我们是属于访问未授权的接口。
增加资源配置
根据官方推荐,是不推荐我们把授权服务器和资源服务器合并在一起的。即授权服务器和资源服务器得分开。
这里我偏偏要合并在一起。理由很简单,我就是不想用微服务。
当然开玩笑的,主要还是自己懒,不想新开一个服务,但是不可否认,对于大部分国内公司、组织、单位、政企来说,以我这个在国企央企呆了8年的人来说,大部分非互联网项目,有些项目,那个微服务的总数,比用户数都多,我接触过一个科技项目,更夸张,微服务的个数,比系统一年的总访问此处加起来都多。
核心代码
增加一个resourceServerSecurityFilterChain的配置,比如我要访问sysOrg/info/{id},那就配置这个接口需要保护起来,保护的方式则为使用jwt验证。
/sysOrg:开头的接口,都需要去验证token是否有效,无效就返回401(之前是访问登录页面)
/api/public:开头的接口,不需要任何认证,直接访问
@Bean@Order(2)public SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http)throws Exception {http.securityMatcher("/sysOrg/**") // 配置需要保护的API路径.authorizeHttpRequests(authorize ->authorize.requestMatchers("/api/public").permitAll() // 公开API.anyRequest().authenticated() // 其他API需要认证).oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()) ); // 启用JWT验证return http.build();}
完整代码
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;@Configuration
@EnableWebSecurity
public class SecurityConfig {@Bean@Order(1)public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http)throws Exception {OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =OAuth2AuthorizationServerConfigurer.authorizationServer();http.securityMatcher(authorizationServerConfigurer.getEndpointsMatcher()).with(authorizationServerConfigurer, (authorizationServer) ->authorizationServer.oidc(Customizer.withDefaults()) // Enable OpenID Connect 1.0).authorizeHttpRequests((authorize) ->authorize.anyRequest().authenticated())// 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.build();}@Bean@Order(2)public SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http)throws Exception {http.securityMatcher("/sysOrg/**") // 配置需要保护的API路径.authorizeHttpRequests(authorize ->authorize.requestMatchers("/api/public").permitAll() // 公开API.anyRequest().authenticated() // 其他API需要认证).oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()) ); // 启用JWT验证return http.build();}@Bean@Order(3)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();}@Beanpublic UserDetailsService userDetailsService() {UserDetails userDetails = User.withDefaultPasswordEncoder().username("hutao").password("2025.com").roles("USER").build();return new InMemoryUserDetailsManager(userDetails);}@Beanpublic RegisteredClientRepository registeredClientRepository() {RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString()).clientId("oidc-client").clientSecret("{noop}secret").clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC).authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN).authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).redirectUri("http://www.baidu.com").postLogoutRedirectUri("http://127.0.0.1:8080/").scope(OidcScopes.OPENID).scope(OidcScopes.PROFILE).clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build()).build();return new InMemoryRegisteredClientRepository(oidcClient);}@Beanpublic 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);}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;}@Beanpublic JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);}@Beanpublic AuthorizationServerSettings authorizationServerSettings() {return AuthorizationServerSettings.builder().build();}}
验证
参照:SpringBoot3集成Oauth2.1——2快速入门获取token
在认证参数中,选择Bearer Token,填入我们获取到的token,即可授权访问
此时token有误,或者直接没传,例如下面的No Auth,就是返回401