当前位置: 首页 > news >正文

Oauth2 自定义设置token过期时间

方法:oauth2设置token过期时间,在配置中重写 DefaultTokenServices 中默认的12小时即可;

框中的是底层jar接口中默认设置的12小时过期;

重写代码如下:

一.重写 DefaultTokenServices,修改有效期参数
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.*;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.*;@Primary
@Component
public class CustomTokenServices extends DefaultTokenServices {private int refreshTokenValiditySeconds = 2592000;// web端 token 有效时间(秒) 24小时private int accessTokenValiditySeconds = 86400;// 移动端 token 有效时间(秒) 7天private int accessTokenValiditySecondsForMobile = 604800;private boolean supportRefreshToken = false;private boolean reuseRefreshToken = true;@Autowiredprivate TokenStore tokenStore;@Autowiredprivate ClientDetailsService clientDetailsService;@Autowiredprivate TokenEnhancer accessTokenEnhancer;@Autowiredprivate AuthenticationManager authenticationManager;public CustomTokenServices() {}public void afterPropertiesSet() throws Exception {Assert.notNull(this.tokenStore, "tokenStore must be set");}@Transactional@Overridepublic OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {OAuth2AccessToken existingAccessToken = this.tokenStore.getAccessToken(authentication);OAuth2RefreshToken refreshToken = null;if (existingAccessToken != null) {if (!existingAccessToken.isExpired()) {this.tokenStore.storeAccessToken(existingAccessToken, authentication);return existingAccessToken;}if (existingAccessToken.getRefreshToken() != null) {refreshToken = existingAccessToken.getRefreshToken();this.tokenStore.removeRefreshToken(refreshToken);}this.tokenStore.removeAccessToken(existingAccessToken);}if (refreshToken == null) {refreshToken = this.createRefreshToken(authentication);} else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken;if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {refreshToken = this.createRefreshToken(authentication);}}OAuth2AccessToken accessToken = this.createAccessToken(authentication, refreshToken);this.tokenStore.storeAccessToken(accessToken, authentication);refreshToken = accessToken.getRefreshToken();if (refreshToken != null) {this.tokenStore.storeRefreshToken(refreshToken, authentication);}return accessToken;}@Transactional(noRollbackFor = {InvalidTokenException.class, InvalidGrantException.class})public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest) throws AuthenticationException {if (!this.supportRefreshToken) {throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);} else {OAuth2RefreshToken refreshToken = this.tokenStore.readRefreshToken(refreshTokenValue);if (refreshToken == null) {throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);} else {OAuth2Authentication authentication = this.tokenStore.readAuthenticationForRefreshToken(refreshToken);if (this.authenticationManager != null && !authentication.isClientOnly()) {Authentication user = new PreAuthenticatedAuthenticationToken(authentication.getUserAuthentication(), "", authentication.getAuthorities());user = this.authenticationManager.authenticate(user);Object details = authentication.getDetails();authentication = new OAuth2Authentication(authentication.getOAuth2Request(), user);authentication.setDetails(details);}String clientId = authentication.getOAuth2Request().getClientId();if (clientId != null && clientId.equals(tokenRequest.getClientId())) {this.tokenStore.removeAccessTokenUsingRefreshToken(refreshToken);if (this.isExpired(refreshToken)) {this.tokenStore.removeRefreshToken(refreshToken);throw new InvalidTokenException("Invalid refresh token (expired): " + refreshToken);} else {authentication = this.createRefreshedAuthentication(authentication, tokenRequest);if (!this.reuseRefreshToken) {this.tokenStore.removeRefreshToken(refreshToken);refreshToken = this.createRefreshToken(authentication);}OAuth2AccessToken accessToken = this.createAccessToken(authentication, refreshToken);this.tokenStore.storeAccessToken(accessToken, authentication);if (!this.reuseRefreshToken) {this.tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);}return accessToken;}} else {throw new InvalidGrantException("Wrong client for this refresh token: " + refreshTokenValue);}}}}public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {return this.tokenStore.getAccessToken(authentication);}private OAuth2Authentication createRefreshedAuthentication(OAuth2Authentication authentication, TokenRequest request) {Set<String> scope = request.getScope();OAuth2Request clientAuth = authentication.getOAuth2Request().refresh(request);if (scope != null && !scope.isEmpty()) {Set<String> originalScope = clientAuth.getScope();if (originalScope == null || !originalScope.containsAll(scope)) {throw new InvalidScopeException("Unable to narrow the scope of the client authentication to " + scope + ".", originalScope);}clientAuth = clientAuth.narrowScope(scope);}OAuth2Authentication narrowed = new OAuth2Authentication(clientAuth, authentication.getUserAuthentication());return narrowed;}protected boolean isExpired(OAuth2RefreshToken refreshToken) {if (!(refreshToken instanceof ExpiringOAuth2RefreshToken)) {return false;} else {ExpiringOAuth2RefreshToken expiringToken = (ExpiringOAuth2RefreshToken) refreshToken;return expiringToken.getExpiration() == null || System.currentTimeMillis() > expiringToken.getExpiration().getTime();}}public OAuth2AccessToken readAccessToken(String accessToken) {return this.tokenStore.readAccessToken(accessToken);}public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException, InvalidTokenException {OAuth2AccessToken accessToken = this.tokenStore.readAccessToken(accessTokenValue);if (accessToken == null) {throw new InvalidTokenException("Invalid access token: " + accessTokenValue);} else if (accessToken.isExpired()) {this.tokenStore.removeAccessToken(accessToken);throw new InvalidTokenException("Access token expired: " + accessTokenValue);} else {OAuth2Authentication result = this.tokenStore.readAuthentication(accessToken);if (result == null) {throw new InvalidTokenException("Invalid access token: " + accessTokenValue);} else {if (this.clientDetailsService != null) {String clientId = result.getOAuth2Request().getClientId();try {this.clientDetailsService.loadClientByClientId(clientId);} catch (ClientRegistrationException var6) {ClientRegistrationException e = var6;throw new InvalidTokenException("Client not valid: " + clientId, e);}}return result;}}}public String getClientId(String tokenValue) {OAuth2Authentication authentication = this.tokenStore.readAuthentication(tokenValue);if (authentication == null) {throw new InvalidTokenException("Invalid access token: " + tokenValue);} else {OAuth2Request clientAuth = authentication.getOAuth2Request();if (clientAuth == null) {throw new InvalidTokenException("Invalid access token (no client id): " + tokenValue);} else {return clientAuth.getClientId();}}}public boolean revokeToken(String tokenValue) {OAuth2AccessToken accessToken = this.tokenStore.readAccessToken(tokenValue);if (accessToken == null) {return false;} else {if (accessToken.getRefreshToken() != null) {this.tokenStore.removeRefreshToken(accessToken.getRefreshToken());}this.tokenStore.removeAccessToken(accessToken);return true;}}private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {if (!this.isSupportRefreshToken(authentication.getOAuth2Request())) {return null;} else {int validitySeconds = this.getRefreshTokenValiditySeconds(authentication.getOAuth2Request());String value = UUID.randomUUID().toString();return (OAuth2RefreshToken) (validitySeconds > 0 ? new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis() + (long) validitySeconds * 1000L)) : new DefaultOAuth2RefreshToken(value));}}private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());int validitySeconds = this.getAccessTokenValiditySeconds(authentication.getOAuth2Request());if (validitySeconds > 0) {token.setExpiration(new Date(System.currentTimeMillis() + (long) validitySeconds * 1000L));}token.setRefreshToken(refreshToken);token.setScope(authentication.getOAuth2Request().getScope());return (OAuth2AccessToken) (this.accessTokenEnhancer != null ? this.accessTokenEnhancer.enhance(token, authentication) : token);}protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {if (this.clientDetailsService != null) {ClientDetails client = this.clientDetailsService.loadClientByClientId(clientAuth.getClientId());Integer validity = client.getAccessTokenValiditySeconds();if (validity != null) {return validity;}}boolean isMobile = isMobileClient();if (isMobile) {return this.accessTokenValiditySecondsForMobile;}return this.accessTokenValiditySeconds;}protected int getRefreshTokenValiditySeconds(OAuth2Request clientAuth) {if (this.clientDetailsService != null) {ClientDetails client = this.clientDetailsService.loadClientByClientId(clientAuth.getClientId());Integer validity = client.getRefreshTokenValiditySeconds();if (validity != null) {return validity;}}return this.refreshTokenValiditySeconds;}protected boolean isSupportRefreshToken(OAuth2Request clientAuth) {if (this.clientDetailsService != null) {ClientDetails client = this.clientDetailsService.loadClientByClientId(clientAuth.getClientId());return client.getAuthorizedGrantTypes().contains("refresh_token");} else {return this.supportRefreshToken;}}public void setTokenEnhancer(TokenEnhancer accessTokenEnhancer) {this.accessTokenEnhancer = accessTokenEnhancer;}public void setRefreshTokenValiditySeconds(int refreshTokenValiditySeconds) {this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;}public void setAccessTokenValiditySeconds(int accessTokenValiditySeconds) {this.accessTokenValiditySeconds = accessTokenValiditySeconds;}public void setSupportRefreshToken(boolean supportRefreshToken) {this.supportRefreshToken = supportRefreshToken;}public void setReuseRefreshToken(boolean reuseRefreshToken) {this.reuseRefreshToken = reuseRefreshToken;}public void setTokenStore(TokenStore tokenStore) {this.tokenStore = tokenStore;}public void setAuthenticationManager(AuthenticationManager authenticationManager) {this.authenticationManager = authenticationManager;}public void setClientDetailsService(ClientDetailsService clientDetailsService) {this.clientDetailsService = clientDetailsService;}}
二.区分设备类型,设置不同的token有效期
1.在重写的DefaultTokenServices类中修改OAuth2Authentication对象参数,增加请求类型判断

实现如下:

/*** 重建认证参数,区分移动/web端 token请求** @param authentication* @return*/private OAuth2Authentication addOauth2AuthenticationSign(OAuth2Authentication authentication) {boolean isMobile = isMobileClient();OAuth2Request oAuth2Request = authentication.getOAuth2Request();Set<String> newScopes = new HashSet<>();for (String scope : oAuth2Request.getScope()) {newScopes.add(scope + "_" + (isMobile ? "mobile" : "web"));}Map<String, Serializable> extensions = oAuth2Request.getExtensions();extensions.put("device_type", isMobile ? "mobile" : "web");OAuth2Request updatedRequest = new OAuth2Request(oAuth2Request.getRequestParameters(),oAuth2Request.getClientId(),oAuth2Request.getAuthorities(),oAuth2Request.isApproved(),newScopes,oAuth2Request.getResourceIds(),oAuth2Request.getRedirectUri(),oAuth2Request.getResponseTypes(),extensions);return new OAuth2Authentication(updatedRequest, authentication.getUserAuthentication());}private boolean isMobileClient() {// 获取当前 HTTP 请求ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();// 没有当前请求上下文if (attributes == null) {return false;}HttpServletRequest request = attributes.getRequest();//User-Agent 判断String userAgent = request.getHeader("User-Agent");if (userAgent != null && (userAgent.contains("Android") || userAgent.contains("iPhone"))) {return true;}return false;}
增加这段代码,在请求生成或获取token时,提前判断设备类型,并修改对应参数以达到效果
三: token请求测试
使用postman修改请求头中的user-agent参数:
Web:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36

App:

Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1

切换不同参数,可以看返回效果不同......

http://www.lryc.cn/news/576820.html

相关文章:

  • 状态机编程实战 | 如何更优雅地处理字符串
  • 全新大模型开源,腾讯(int4能打DeepSeek) Vs 谷歌(2GB运行多模态)
  • Gemini-CLI:谷歌开源的命令行AI工具,重新定义开发者工作流
  • Ubuntu22 安装 RTX 5070 Ti Nvidia Driver 驱动
  • 自学嵌入式 day27 进程
  • mac系统快捷键及命令安装
  • 状态模式 - Flutter中的状态变身术,让对象随“状态“自由切换行为!
  • 边界的艺术:支持向量机与统计学习时代的王者
  • 设计模式-外观模式、适配器模式
  • 【数据挖掘】聚类算法学习—K-Means
  • YOLOv12_ultralytics-8.3.145_2025_5_27部分代码阅读笔记-conv.py
  • 设备预测性维护和异常检测系统设计方案
  • 【HuggingFace】模型下载至本地访问
  • Git安装全攻略:避坑指南与最佳实践
  • C++ 格式化输入输出
  • 人工智能时代的职业替代风险与应对策略分析
  • MySQL技巧
  • 性能分析专栏 -- top命令
  • 【修电脑的小记录】连不上网
  • 打造地基: App拉起基础小程序容器
  • 疏通经脉: Bridge 联通逻辑层和渲染层
  • 深入理解 Dubbo 负载均衡:原理、源码与实践
  • RK3588集群服务器性能优化案例:电网巡检集群、云手机集群、工业质检集群
  • [Python 基础课程]PyCharm 的安装
  • 大数据Hadoop之——Flume安装与使用(详细)
  • Dify私有化知识库搭建并通过ChatFlow智能机器人使用知识库的详细操作步骤
  • AlpineLinux安装部署MariaDB
  • 怎样优化HDFS的网络传输
  • WireShark网络取证分析第一集到第五集和dvwa靶场环境分析漏洞
  • TCP/IP模型、OSI模型与C# Socket编程详解