springboot刷新token时长

前言

核心:

根据用户生成token,返回前端,对于后续每一次操作都携带token,如果token存在就进行刷新,我设置的token时间为30分钟,如果用户30分钟内没有任何操作,就让其重新登录。

实现逻辑:

1.正常:前端传入token --> 后端拦截获取token --> redis验证token --> 获取到值 --> 更新时长并放行

2.异常:redis验证token --> 获取不到值 --> jwt验证token是否正确 --> 正确则返回用户长时间未操作,不正确则返回非法token

正文

1.所需依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>mybatis-plus-boot-starter</artifactId>
   <version>3.5.2</version>
</dependency>

<dependency>
   <groupId>com.mysql</groupId>
   <artifactId>mysql-connector-j</artifactId>
   <scope>runtime</scope>
</dependency>

<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <optional>true</optional>
</dependency>
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>fastjson</artifactId>
   <version>1.2.37</version>
</dependency>

<dependency>
   <groupId>com.auth0</groupId>
   <artifactId>java-jwt</artifactId>
   <version>3.10.0</version>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.配置信息

#mysql数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/crm?characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
#Redis数据库配置
spring.redis.port=6379
spring.redis.host=192.168.57.128
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-wait=-1
#token过期时间
token.expires=3600

3.用户登录实现

具体逻辑

1.根据前端传输的用户信息进行校验,判断用户是否存在,密码是否正确

        校验密码这块请前往spring对密码的处理拷贝即可

2.设置基础信息AuthInfo,这个类交给spring管理,方便后续直接取用

3.JwtUtil生成token, 存入redis中,代码中的Constants.TOKEN_PREFIXsys:user:token:

4.返回token给前端

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

//这里引入依赖,配置了基本的信息就可以直接注入使用

@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Value("${token.expires}")
private long expires;
@Override
public LoginVO login(LoginDTO loginDTO) {
//判断用户是否存在
User user = getOne(User.gw().eq(User::getUserName, loginDTO.getUsername()));
if (Objects.isNull(user)) {
    //这可以写注册的逻辑
    throw new ServiceException("用户不存在");
}
//校验密码
boolean b = PasswordEncode.matches(loginDTO.getPassword(), user.getUserPassword());
if (!b) {
    throw new ServiceException("密码错误");
}
/**
 * 设置基础信息,方便后续使用
 */
AuthInfo authInfo = SpringUtil.getBean(AuthInfo.class);
authInfo.setDeptId(user.getDeptId());
authInfo.setRoleId(user.getRoleId());
authInfo.setUserId(user.getUserId());
authInfo.setUsername(user.getUserName());
//生成token
String token = JwtUtil.getToken(user);
//存入redis
try {
    ValueOperations valueOperations = redisTemplate.opsForValue();
    valueOperations.set(Constants.TOKEN_PREFIX + token, authInfo,  expires, TimeUnit.MINUTES);
} catch (Exception e) {
    throw new RedisException("redis缓存Token失败");
}
return LoginVO.builder().token(token).build();

}

}

 实体类

实体类根据自己项目所需进行编写,把上面代码换成自己的即可

工具类

JwtUtil

@Component
public class JwtUtil {
/**
 * 生成token
 *
 * @param user
 * @return
 */
public static String getToken(User user) {
    return JWT.create()
            .withClaim("username", user.getUserName())
            .withExpiresAt(DateUtil.offsetMinute(new Date(), 30))
            .sign(Algorithm.HMAC256(user.getUserPassword()));
}
/**
 * 刷新token就是重新设置时间
 *
 * @param token
 * @param authInfo
 * @return
 */
public static boolean refreshToken(String token, AuthInfo authInfo) {
    try {
        RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set(Constants.TOKEN_PREFIX + token, authInfo, JwtUtil.exp, TimeUnit.MINUTES);
        return true;
    } catch (Exception e) {
        return false;
    }
}

public static boolean verify(String token) {
    AuthInfo authInfo = SpringUtil.getBean(AuthInfo.class);
    User user = uService.getById(authInfo.getUserId());
    // 验证 token
    JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getUserPassword())).build();
    return Objects.nonNull(jwtVerifier.verify(token));
}

}

4.拦截验证

具体逻辑

1.验证请求是否携带token

2.根据tokenredis中取出AuthInfo,代码中的Constants.TOKEN_PREFIXsys:user:token:

        1.如果取不到,就使用jwt验证token。

        2.如果取到,就重新设置token时长,保存到redis中。

public class TokenVerify implements HandlerInterceptor {
    
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    //校验请求头token
    String token = request.getHeader("token");
    if (StringUtils.isEmpty(token)) {
        throw new TokenException("未携带Token");
    }
    /**
     * 校验token
     */
    //先从redis去验证
    RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
    AuthInfo authInfo = (AuthInfo)redisTemplate.opsForValue().get(Constants.TOKEN_PREFIX + token);
    if (Objects.isNull(authInfo)) {
        //验证是否合法
        try {
            JwtUtil.verify(token);
        } catch (TokenExpiredException e) {
            //这里我们不处理,刷新token只针对redis中的token
        }catch (JWTException e) {
            throw new JWTException("非法token");
        }
        throw new TokenException("token已过期,请重新登录");
    }

    //服务器宕机导致用户数据丢失
    if (Objects.isNull(SpringUtil.getBean(AuthInfo.class).getUserId())) {
        throw new RuntimeException("服务器异常,请重新登录");
    }
    //刷新token时长
    if (!JwtUtil.refreshToken(Constants.TOKEN_PREFIX + token, authInfo)) {
        throw new TokenException("刷新token失败");
    }
    return true;
}
}

5. 注册拦截器

具体逻辑

 1.注册拦截器,并且对登录和验证码接口放行

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
    //验证token
    registry.addInterceptor(new TokenVerify())
            .addPathPatterns("/api/**")
            .excludePathPatterns(
                    Urls.User.LOGIN, Urls.User.CAPTCHA);
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值