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

Spring Security REST:账号过期时如何失效Refresh Token?

解决Spring Security REST中账号过期后移动端Token未失效的问题

针对你遇到的账号过期(accountExpired=true)后移动端Token仍有效的问题,可通过以下几种方案实现权限终止:

方案1:自定义请求过滤器,实时校验用户状态

Spring Security REST默认仅在获取Token时校验用户状态,后续请求不再检查。我们可以添加一个过滤器,在每次API请求时重新校验用户的accountExpired状态,一旦发现账号过期立即拒绝访问。

实现步骤:

  1. 创建自定义过滤器类
class AccountStatusCheckFilter extends OncePerRequestFilter {
    def userService

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication()
        if (auth?.principal instanceof User) {
            // 从数据库拉取最新的用户状态,避免缓存导致的状态不一致
            User latestUser = userService.get(auth.principal.id)
            if (latestUser?.accountExpired) {
                SecurityContextHolder.clearContext()
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "账号已过期")
                return
            }
        }
        filterChain.doFilter(request, response)
    }
}
  1. 注册过滤器Bean
    在grails-app/conf/spring/resources.groovy中添加:
accountStatusCheckFilter(AccountStatusCheckFilter) {
    userService = ref('userService')
}
  1. 将过滤器加入Spring Security链
    修改grails-app/conf/application.groovy中的Spring Security配置:
grails.plugin.springsecurity.filterChain.chainMap = [
    '/api/**': 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter',
    '/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter'
]

grails.plugin.springsecurity.filterChain.filterNames = [
    'securityContextPersistenceFilter',
    'restTokenValidationFilter',
    'accountStatusCheckFilter', // 放在Token验证过滤器之后
    'filterSecurityInterceptor'
]

方案2:维护Token黑名单,账号过期时禁用所有有效Token

如果使用的是持久化存储的Token(如数据库存储)或JWT,可通过黑名单机制直接禁用用户的所有有效Token。

实现步骤:

  1. 创建Token黑名单实体
class TokenBlacklist {
    String tokenValue
    Date expirationDate
    Date dateCreated

    static constraints = {
        tokenValue unique: true
    }
}
  1. 编写黑名单服务
class TokenBlacklistService {
    boolean isBlacklisted(String token) {
        return TokenBlacklist.existsByTokenValue(token)
    }

    void addToBlacklist(String token, Date expirationDate) {
        new TokenBlacklist(tokenValue: token, expirationDate: expirationDate).save(flush: true)
        // 定期清理过期的黑名单记录
        TokenBlacklist.where { expirationDate < new Date() }.deleteAll()
    }
}
  1. 账号过期时批量加入黑名单
    在设置用户accountExpired=true时,同步将该用户的所有有效Token加入黑名单:
def disableUser(User user) {
    user.accountExpired = true
    user.save(flush: true)
    
    // 假设你用了数据库存储的Refresh Token,替换为你的Token实体类
    def activeTokens = RefreshToken.where { user == user && expiration > new Date() }.list()
    activeTokens.each { token ->
        tokenBlacklistService.addToBlacklist(token.token, token.expiration)
    }
}
  1. 在Token验证环节校验黑名单
    如果用JWT,自定义Token服务类:
class CustomJwtTokenService extends DefaultJwtTokenService {
    def tokenBlacklistService

    @Override
    protected Authentication parseToken(String token) {
        if (tokenBlacklistService.isBlacklisted(token)) {
            throw new InvalidTokenException("Token已被禁用")
        }
        super.parseToken(token)
    }
}

方案3:缩短Access Token有效期,强制刷新时校验用户状态

将Access Token的有效期设短(如15分钟),用户需要频繁用Refresh Token刷新新的Access Token。而Spring Security REST在刷新Token时会重新校验用户状态,此时若accountExpired=true,会直接拒绝刷新请求,旧Token过期后用户无法继续访问。

配置示例(application.groovy):

grails.plugin.springsecurity.rest.token.storage.useJwt = true
grails.plugin.springsecurity.rest.token.jwt.expiration = 900 // Access Token有效期15分钟
grails.plugin.springsecurity.rest.token.refresh.useJwt = true
grails.plugin.springsecurity.rest.token.refresh.jwt.expiration = 86400 // Refresh Token有效期1天

方案选择建议

  • 若需要立即终止权限:优先选择方案1+方案2,既实时拦截请求,又禁用已发出的Token。
  • 若可接受短时间延迟:方案3配置最简单,仅需调整Token有效期,依赖Refresh Token刷新时的状态校验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 21:22:46