SpringBoot3.X配置OAuth

      背景

        之前在学习OAuth2时,我就有一个疑惑,OAuth2中有太多的配置、服务类都标注了@Deprecated,如下:

        显然这些写法已经过时了,那么官方推荐的最新写法是什么样的呢?当时我没有深究这些,我以为我放过了它,它就能放过我,谁曾想不久之后,命运的大手不由分说的攥紧了我,让我不得不直面自己的困惑。

        最近我接了个大活,对公司的Java后端技术框架进行版本升级,将SpringBoot的版本从2.X升到3.X,JDK从1.8升到17,在对框架的父工程中的依赖版本进行升级之后,接下来要做的就是对已有的公共服务/组件进行升级了,比如GateWay, 流程引擎,基础平台,认证服务等。其他的服务升级都还算有惊无险,但是升级认证服务OAuth时,不夸张的说,我真是被折腾得死去活来。

        相比于SpringBoot2.X,3.X对于OAuth的配置几乎是进行了巅覆式的变更,很多之前我们熟知的配置方法,要么是换了形式,要么是换了位置,想要配得和2.X一样的效果太难了。好在经历了一番坎坷后,我终于把它给整理出来了,借着OAuth升版的机会,我也终于弄明白了最版的配置是什么样的。

      代码实践

        伴随着JDK和SpringBoot的版本升级,Spring Security也需要进行相应的升级,这直接导致了适用于SpringBoot2.X的相关OAuth配置变得不可用,甚至我们耳熟能详的配置类如AuthorizationServerConfigurerAdapter, WebSecurityConfigurerAdapter等都被删除了,下面就对比着SpringBoot2.X,详细说下3.X中对于配置做了哪些变更。

      一、依赖包的变化

        在SpringBoot2.X中要实现OAuth服务,需要引入以下依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.3.2.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

        而在SpringBoot3.X中,需要引入以下依赖包:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-oauth2-authorization-server</artifactId>
      <version>1.0.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-oauth2-core</artifactId>
    </dependency>

      二、支持模式的变化

        新版的spring-security-oauth2-authorization-server依赖包中,仅实现了授权码模式,要想使用之前的用户名密码模式,客户端模式等,还需要手动扩展,扩展模式需要实现这三个接口:

        AuthenticationConverter (用于将认证请求转换为标准的 Authentication 对象)

        AuthenticationProvider (用于定义如何验证用户的认证信息)

        OAuth2AuthorizationGrantAuthenticationToken(将认证对象转换为系统内部可识别的形式)

      三、数据库表的变化

        SpringBoot2.X版本时,OAuth存储客户信息的表结构如下:

create table oauth_client_details (
    client_id VARCHAR(256) PRIMARY KEY,
	resource_ids VARCHAR(256),
	client_secret VARCHAR(256),
	scope VARCHAR(256),
	authorized_grant_types VARCHAR(256),
	web_server_redirect_uri VARCHAR(256),
	authorities VARCHAR(256),
	access_token_validity INTEGER,
	refresh_token_validity INTEGER,
	additional_information VARCHAR(4096),
	autoapprove VARCHAR(256)
);

        升级为SpringBoot3.X后,客户信息表结构如下:

CREATE TABLE oauth2_registered_client (
    id varchar(100) NOT NULL,
    client_id varchar(100) NOT NULL,
    client_id_issued_at timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
    client_secret varchar(200) DEFAULT NULL,
    client_secret_expires_at timestamp DEFAULT NULL,
    client_name varchar(200) NOT NULL,
    client_authentication_methods varchar(1000) NOT NULL,
    authorization_grant_types varchar(1000) NOT NULL,
    redirect_uris varchar(1000) DEFAULT NULL,
    scopes varchar(1000) NOT NULL,
    client_settings varchar(2000) NOT NULL,
    token_settings varchar(2000) NOT NULL,
    PRIMARY KEY (id)
);

        四、链接的变化

           旧版本的OAuth服务中,相关的认证接接口的url都是/oauth/*,如/oauth/token /oauth/authorize,而升级到新版后,所有接口的url都变成了/oauth2/*,在配置客户端时需要格外注意。

      五、配置的变化

        接下来就是重头戏:配置的变化,为了更直观的展示SprinBoot在2.X和3.X对于配置的变化,我将把一套2.X的OAuth配置以及它转换成3.X的配置都贴出来,配置中涉及认证自动审批、内存模式和数据库模式,Token的过期时间,Token的JWT转换,Password的加密,自定义登陆页,客户端的授权方式等。

        1、SpringBoot2.X的配置


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Arrays;

/**
 *
 * @author leixiyueqi
 * @since 2023/12/3 22:00
 */
@EnableAuthorizationServer
@Configuration
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {

    @Resource
    private AuthenticationManager manager;

    private final MD5PasswordEncoder encoder = new MD5PasswordEncoder();

    @Resource
    UserDetailsService service;

    @Resource
    private DataSource dataSource;

    @Resource
    TokenStore tokenStore;


    /**
     * 这个方法是对客户端进行配置,比如秘钥,唯一id,,一个验证服务器可以预设很多个客户端,
     * 之后这些指定的客户端就可以按照下面指定的方式进行验证
     * @param clients 客户端配置工具
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    /**
     * 以内存的方式设置客户端方法

     @Override
     public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
         clients
             .inMemory()   //这里我们直接硬编码创建,当然也可以像Security那样自定义或是使用JDBC从数据库读取
             .withClient("client")   //客户端名称,随便起就行
             .secret(encoder.encode("123456"))      //只与客户端分享的secret,随便写,但是注意要加密
             .autoApprove(false)    //自动审批,这里关闭,要的就是一会体验那种感觉
             .scopes("read", "write")     //授权范围,这里我们使用全部all
             .autoApprove(true)    // 这个为true时,可以自动授权。
             .redirectUris("http://127.0.0.1:19210/leixi/login/oauth2/code/leixi-client",
             "http://127.0.0.1:8081/login/oauth2/code/client-id-1",
             "http://127.0.0.1:19210/leixi/callback")
             .authorizedGrantTypes("client_credentials", "password", "implicit", "authorization_code", "refresh_token");
             //授权模式,一共支持5种,除了之前我们介绍的四种之外,还有一个刷新Token的模式
     }

     */

    // 令牌端点的安全配置,比如/oauth/token对哪些开放
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security
                .passwordEncoder(encoder)    //编码器设定为BCryptPasswordEncoder
                .allowFormAuthenticationForClients()  //允许客户端使用表单验证,一会我们POST请求中会携带表单信息
                .checkTokenAccess("permitAll()");     //允许所有的Token查询请求
    }

    //令牌访问端点的配置
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {

        endpoints
                .userDetailsService(service)
                .authenticationManager(manager)
                .tokenServices(tokenServices());
        //由于SpringSecurity新版本的一些底层改动,这里需要配置一下authenticationManager,才能正常使用password模式
        endpoints.pathMapping("/oauth/confirm_access","/custom/confirm_access");
    }

    // 设置token的存储,过期时间,添加附加信息等
    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        services.setReuseRefreshToken(true);
        services.setTokenStore(tokenStore);
        services.setAccessTokenValiditySeconds(120);   // 设置令牌有效时间
        services.setRefreshTokenValiditySeconds(60*5);  //设计刷新令牌的有效时间
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(new CustomTokenEnhance
在 Spring Boot 3.x 中继承 OAuth 客户端模式,你可以按照以下步骤进行操作: 1. 首先,确保你已经在你的 Spring Boot 3.x 项目中添加了 Spring Security 和 OAuth2 的依赖。 2. 创建一个配置类,用于配置 OAuth2 的客户端信息。你可以在该类中配置客户端的 ID、密钥、授权类型等信息。示例代码如下: ```java @Configuration @EnableOAuth2Client public class OAuth2ClientConfig { @Value("${oauth2.client.client-id}") private String clientId; @Value("${oauth2.client.client-secret}") private String clientSecret; @Value("${oauth2.client.access-token-uri}") private String accessTokenUri; @Value("${oauth2.client.grant-type}") private String grantType; @Bean public OAuth2ProtectedResourceDetails oauth2ClientCredentials() { ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails(); details.setClientId(clientId); details.setClientSecret(clientSecret); details.setAccessTokenUri(accessTokenUri); details.setGrantType(grantType); return details; } @Bean public OAuth2RestTemplate oauth2RestTemplate(OAuth2ProtectedResourceDetails resourceDetails) { return new OAuth2RestTemplate(resourceDetails); } } ``` 3. 配置 OAuth2 的授权服务器信息。在 application.properties 或 application.yml 文件中添加以下属性: ``` oauth2.client.client-id=your-client-id oauth2.client.client-secret=your-client-secret oauth2.client.access-token-uri=your-access-token-uri oauth2.client.grant-type=client_credentials ``` 确保将上述属性值替换为你实际的授权服务器信息。 4. 创建一个服务类,用于调用受保护资源。你可以使用 `OAuth2RestTemplate` 类来发送 HTTP 请求并获取受保护资源的响应。示例代码如下: ```java @Service public class ProtectedResourceService { @Autowired private OAuth2RestTemplate restTemplate; public String getProtectedResource() { ResponseEntity<String> response = restTemplate.exchange( "https://api.example.com/resource", HttpMethod.GET, null, String.class); return response.getBody(); } } ``` 在上述代码中,`https://api.example.com/resource` 是你想要获取的受保护资源的 URL。 现在,你可以在其他组件中注入 `ProtectedResourceService` 并调用 `getProtectedResource()` 方法来获取受保护资源了。 请注意,以上代码仅为示例,你需要根据你的实际需求进行相应的配置和修改。希望这能帮助到你!如果有任何疑问,请随时提问。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值