You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security OAuth2:如何从数据库读取accessTokenValiditySeconds配置客户端?

实现从数据库读取accessTokenValiditySeconds的方案

嘿,这事儿不难,我给你一步步拆解怎么把硬编码的accessToken有效期改成从数据库读取:

1. 准备数据库表

首先得建一张存储客户端配置的表,把原来硬编码的字段都存进去,比如:

CREATE TABLE oauth_client_details (
    client_id VARCHAR(255) PRIMARY KEY COMMENT '客户端ID',
    client_secret VARCHAR(255) NOT NULL COMMENT '客户端密钥',
    access_token_validity_seconds INT COMMENT 'access_token有效期(秒)',
    refresh_token_validity_seconds INT COMMENT 'refresh_token有效期(秒)',
    scope VARCHAR(255) COMMENT '权限范围,逗号分隔',
    authorized_grant_types VARCHAR(255) COMMENT '授权类型,逗号分隔'
);

然后插入你的测试数据:

INSERT INTO oauth_client_details 
(client_id, client_secret, access_token_validity_seconds, refresh_token_validity_seconds, scope, authorized_grant_types)
VALUES 
('javadeveloperzone', 'secretcode', 3600, -1, 'read,write', 'password,refresh_token');

注意:生产环境下client_secret一定要加密存储,比如用BCrypt加密后再存。

2. 创建实体类映射数据库表

写个JPA实体类对应上面的表:

import javax.persistence.*;

@Entity
@Table(name = "oauth_client_details")
public class OauthClientDetails {
    @Id
    @Column(name = "client_id")
    private String clientId;

    @Column(name = "client_secret")
    private String clientSecret;

    @Column(name = "access_token_validity_seconds")
    private Integer accessTokenValiditySeconds;

    @Column(name = "refresh_token_validity_seconds")
    private Integer refreshTokenValiditySeconds;

    @Column(name = "scope")
    private String scope;

    @Column(name = "authorized_grant_types")
    private String authorizedGrantTypes;

    // 生成所有字段的getter和setter方法
}

3. 编写数据访问Repository

用Spring Data JPA写个Repository接口,方便操作数据库:

import org.springframework.data.jpa.repository.JpaRepository;

public interface OauthClientDetailsRepository extends JpaRepository<OauthClientDetails, String> {
}

4. 自定义ClientDetailsService

Spring Security OAuth2默认的InMemoryClientDetailsService是从内存读配置,我们需要自己实现一个从数据库读取的:

import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CustomClientDetailsService implements ClientDetailsService {

    private final OauthClientDetailsRepository clientDetailsRepository;

    // 构造注入Repository
    public CustomClientDetailsService(OauthClientDetailsRepository clientDetailsRepository) {
        this.clientDetailsRepository = clientDetailsRepository;
    }

    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        // 根据clientId从数据库查询配置
        OauthClientDetails dbClient = clientDetailsRepository.findById(clientId)
                .orElseThrow(() -> new ClientRegistrationException("客户端不存在:" + clientId));

        // 把数据库实体转换成OAuth2需要的ClientDetails对象
        return org.springframework.security.oauth2.provider.client.BaseClientDetails.builder()
                .clientId(dbClient.getClientId())
                .clientSecret(dbClient.getClientSecret())
                .accessTokenValiditySeconds(dbClient.getAccessTokenValiditySeconds())
                .refreshTokenValiditySeconds(dbClient.getRefreshTokenValiditySeconds())
                .scopes(parseStringToList(dbClient.getScope()))
                .authorizedGrantTypes(parseStringToList(dbClient.getAuthorizedGrantTypes()))
                .build();
    }

    // 把逗号分隔的字符串转换成列表
    private List<String> parseStringToList(String str) {
        if (str == null || str.isEmpty()) {
            return List.of();
        }
        return Arrays.stream(str.split(","))
                .map(String::trim)
                .collect(Collectors.toList());
    }
}

5. 修改AuthorizationServer配置

把原来的内存配置替换成我们自定义的CustomClientDetailsService:

import org.springframework.context.annotation.Configuration;
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;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    private final CustomClientDetailsService customClientDetailsService;

    public AuthorizationServerConfig(CustomClientDetailsService customClientDetailsService) {
        this.customClientDetailsService = customClientDetailsService;
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 替换为自定义的ClientDetailsService,从数据库读取配置
        clients.withClientDetails(customClientDetailsService);
    }

    // 如果有密码编码器的需求,这里可以配置,比如:
    // @Bean
    // public PasswordEncoder passwordEncoder() {
    //     return new BCryptPasswordEncoder();
    // }
    // 然后在configure方法里加上:clients.passwordEncoder(passwordEncoder());
}

最后说明

这样配置完之后,授权服务器每次处理客户端请求时,都会从数据库读取access_token_validity_seconds的值,以后要修改有效期,直接改数据库里的记录就行,不用改代码重启服务啦~

内容的提问来源于stack exchange,提问作者user3442057

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:03:20