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
相关产品推荐
相关产品推荐

