Backend Development 7 min read

Implementing Automatic Token Renewal in a Java Backend

This article explains why short-lived JWT tokens need automatic renewal, outlines a Redis‑based solution, and provides complete Spring interceptor and utility code to create, verify, and refresh tokens without forcing users to re‑login frequently.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Implementing Automatic Token Renewal in a Java Backend

Token‑based authentication often sets short expiration times for security, which can inconvenience users; automatic token renewal mitigates this by extending token validity transparently.

The implementation stores the JWT in Redis with a TTL twice the token's expiration and uses a Spring interceptor to check and refresh the token when it expires but the user is still active.

Key code for creating a token and storing it in Redis:

//创建token
String token = JwtUtil.createToken(sysUser.getId(), user.getUserName());
//将token放入redis中,key为用户的手机号+"token"
redisUtil.set(sysUser.getPhone() + GlobalConstant.TOKEN, token, JwtUtil.EXPIRE_TIME * 2);

The interceptor overrides preHandle to validate the token, retrieve the user, and invoke refreshToken :

@Component
public class LoginInterceptor implements HandlerInterceptor {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Resource
    private SysUserDao sysUserDao;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private HttpServletRequest request;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        logger.info("进入拦截器 uri:" + request.getRequestURI());
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        PreAuth preAuth = handlerMethod.getMethodAnnotation(PreAuth.class);
        if (preAuth == null) {
            return true;
        }
        Long userId = JwtUtil.getUserIdByToken(request);
        SysUser sysUser = sysUserDao.selectById(userId);
        if (sysUser == null) {
            logger.error("用户不存在");
            return false;
        }
        if (!refreshToken(sysUser)) {
            return false;
        }
        Set
authList = this.sysUserDao.queryAuthList(userId);
        if (!authList.contains(preAuth.value())) {
            logger.error("无权限");
            return false;
        }
        return true;
    }

    /**
     * token自动续期
     * @param sysUser 用户实体
     * @return 是否刷新成功
     */
    private boolean refreshToken(SysUser sysUser) {
        String token = request.getHeader(GlobalConstant.TOKEN);
        String cacheToken = (String) (redisUtil.get(sysUser.getPhone() + GlobalConstant.TOKEN));
        if (StringUtil.isEmpty(token)) {
            logger.error("请求头中token不存在");
            return false;
        }
        if (StringUtil.isEmpty(cacheToken)) {
            logger.error("用户未登录");
            return false;
        }
        try {
            JwtUtil.verify(token);
        } catch (TokenExpiredException tokenExpiredException) {
            if (cacheToken.equals(token)) {
                // 重新刷新redis中的token的过期时间
                redisUtil.set(sysUser.getPhone() + GlobalConstant.TOKEN, token, JwtUtil.EXPIRE_TIME * 60 * 2);
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            logger.error("token不合法");
            return false;
        }
        return true;
    }
}

The JwtUtil utility class creates, verifies, and extracts information from JWTs:

import com.admin.common.constant.GlobalConstant;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import javax.servlet.http.HttpServletRequest;
import java.util.Calendar;
import java.util.Date;

public class JwtUtil {
    /** token私钥,不可以暴露 */
    public static final String TOKEN_SECRET_KEY = "tokenSecretKey";
    /** token过期时间(秒) */
    public static final int EXPIRE_TIME = 60;

    /** 创建token */
    public static String createToken(Long userId, String userName) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, EXPIRE_TIME);
        return JWT.create()
                .withAudience(userId + "")
                .withClaim("userName", userName)
                .withIssuedAt(new Date())
                .withExpiresAt(calendar.getTime())
                .sign(Algorithm.HMAC256(TOKEN_SECRET_KEY));
    }

    /** 验证token合法性 */
    public static void verify(String token) {
        JWT.require(Algorithm.HMAC256(TOKEN_SECRET_KEY)).build().verify(token);
    }

    /** 通过token获取userId */
    public static Long getUserIdByToken(HttpServletRequest request) {
        String token = request.getHeader(GlobalConstant.TOKEN);
        String userId = JWT.decode(token).getAudience().get(0);
        return Long.valueOf(userId);
    }
}

Source: blog.csdn.net/dreaming9420/article/details/121750732.

backendJavaRedisSpringauthenticationJWTToken Renewal
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.