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

Spring Boot 1.5.7 OAuth(password授权)下延长Access Token过期时间方法

实现Spring Boot OAuth2 Access Token滑动过期(闲置过期)

针对你的需求——让Access Token仅在连续15分钟未被调用时过期(也就是滑动过期),在Spring Boot 1.5.7 + Spring Security OAuth 2.x的环境下,可以通过自定义TokenStore来实现核心逻辑,下面是具体的步骤和代码示例:

核心思路

默认的OAuth2 Access Token是固定有效期,不管是否被使用都会按时过期。要实现“闲置过期”,我们需要在每次API调用验证token时,动态更新token的过期时间(重置为当前时间+15分钟)。这就需要我们重写TokenStore的token读取逻辑,在读取token时触发过期时间的更新。


步骤1:自定义TokenStore

根据你使用的token存储方式(内存/数据库),选择对应的父类进行扩展:

方式1:内存存储(单实例场景)

继承InMemoryTokenStore,重写readAccessToken方法,在读取token时更新过期时间:

import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.InMemoryTokenStore;
import java.util.Date;

public class SlidingExpirationTokenStore extends InMemoryTokenStore {

    // Access Token闲置有效期:15分钟(900秒)
    private final int idleValiditySeconds = 900;
    // Access Token最大有效期:可选,比如24小时,防止token永久有效
    private final int maxValiditySeconds = 86400;

    @Override
    public OAuth2AccessToken readAccessToken(String tokenValue) {
        OAuth2AccessToken token = super.readAccessToken(tokenValue);
        if (token != null && !token.isExpired()) {
            // 获取token创建时间(需要配合TokenEnhancer添加该字段)
            Date creationTime = new Date((Long) token.getAdditionalInformation().get("created"));
            long timeElapsed = System.currentTimeMillis() - creationTime.getTime();

            // 未超过最大有效期时,更新闲置过期时间
            if (timeElapsed < maxValiditySeconds * 1000) {
                Date newExpiration = new Date(System.currentTimeMillis() + idleValiditySeconds * 1000);
                token.setExpiration(newExpiration);
                // 重新存储更新后的token
                storeAccessToken(token, token.getAuthentication());
            }
        }
        return token;
    }
}

方式2:数据库存储(分布式场景)

如果是多实例部署,建议使用JdbcTokenStore,重写方法时更新数据库中的过期时间:

import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.JdbcTokenStore;
import javax.sql.DataSource;
import java.util.Date;

public class SlidingJdbcTokenStore extends JdbcTokenStore {

    private final int idleValiditySeconds = 900;
    private final int maxValiditySeconds = 86400;

    public SlidingJdbcTokenStore(DataSource dataSource) {
        super(dataSource);
    }

    @Override
    public OAuth2AccessToken readAccessToken(String tokenValue) {
        OAuth2AccessToken token = super.readAccessToken(tokenValue);
        if (token != null && !token.isExpired()) {
            Date creationTime = new Date((Long) token.getAdditionalInformation().get("created"));
            long timeElapsed = System.currentTimeMillis() - creationTime.getTime();

            if (timeElapsed < maxValiditySeconds * 1000) {
                Date newExpiration = new Date(System.currentTimeMillis() + idleValiditySeconds * 1000);
                token.setExpiration(newExpiration);
                // 更新数据库中的过期时间字段
                getJdbcTemplate().update(
                        "UPDATE oauth_access_token SET expiration = ? WHERE token_id = ?",
                        newExpiration, extractTokenKey(tokenValue));
            }
        }
        return token;
    }
}

步骤2:添加TokenEnhancer记录创建时间

要判断token是否超过最大有效期,我们需要在token创建时记录它的生成时间,这可以通过自定义TokenEnhancer实现:

import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import java.util.HashMap;
import java.util.Map;

public class CustomTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        Map<String, Object> additionalInfo = new HashMap<>();
        // 添加token创建时间戳
        additionalInfo.put("created", System.currentTimeMillis());
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
        return accessToken;
    }
}

步骤3:配置授权服务器

在你的AuthorizationServerConfig中,替换默认的TokenStore,并配置TokenEnhancer:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired(required = false)
    private DataSource dataSource; // 数据库存储时需要

    // 配置自定义TokenStore
    @Bean
    public TokenStore tokenStore() {
        // 单实例用内存存储
        // return new SlidingExpirationTokenStore();
        // 分布式用数据库存储
        return new SlidingJdbcTokenStore(dataSource);
    }

    // 配置TokenEnhancerChain
    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new CustomTokenEnhancer();
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer()));

        endpoints
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .tokenStore(tokenStore())
                .tokenEnhancer(tokenEnhancerChain);
    }

    // 其他必要配置:客户端信息、密码编码器等
    // ...
}

注意事项

  1. 安全风险控制:设置最大有效期很重要,避免用户持续调用API导致token永久有效,建议根据业务场景设置合理的最大有效期(比如24小时)。
  2. 分布式场景一致性:如果使用数据库存储,要确保所有实例都连接同一个数据库,避免token状态不一致。
  3. 性能考虑:每次API调用都会触发token过期时间的更新,对于高并发场景,可以考虑优化数据库更新逻辑(比如设置阈值,只有当剩余有效期小于5分钟时才更新)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:39:11