SpringBoot集成 Jwt 实现Token验证访问

一: 导入依赖

	<!--  jwt   -->
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt</artifactId>
      <version>0.7.0</version>
    </dependency>

二: 设置jwt配置类

package com.lemon.move.utils;
 
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import org.springframework.stereotype.Component;
 
/**
 * token 工具类
 */
@Component
public class JwtUtils {
 
  // 过期时间 一小时 毫秒
  private static long expire = 3600000;
  // 秘钥 
  private static String secret = "HSyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9";
 
  /**
   * 创建一个token
   *
   * @param userId
   * @return
   */
  public String generateToken(String userId) {
    Date now = new Date();
    Date expireDate = new Date(now.getTime() + expire);
    return Jwts.builder().setHeaderParam("type", "JWT").setSubject(userId).setIssuedAt(now)
        .setExpiration(expireDate).signWith(
            SignatureAlgorithm.HS512, secret).compact();
  }
 
  /**
   * 解析token
   */
  public Claims getClaimsByToken(String token) {
    try {
      return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
    } catch (Exception e) {
      System.out.println("validate is token error");
      return null;
    }
  }
 
  /**
   * 判断 token 是否过期
   */
  public boolean isTokenExpired(Date expiration){
    return expiration.before(new Date());
  }
}

三: 配置jwt的拦截器

package com.lemon.move.interceptor;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.lemon.move.common.exception.BusinessException;
import com.lemon.move.common.exception.UnifiedExceptionHandler;
import com.lemon.move.common.result.R;
import com.lemon.move.common.result.ResponseEnum;
import com.lemon.move.config.CommonConfig;
import com.lemon.move.utils.JwtUtils;
import com.lemon.move.utils.RedisUtil;
import io.jsonwebtoken.Claims;

import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 * 创建一个 token 拦截器.
 * 需要继承 HandlerInterceptorAdapter,并且声明为spring的组件
 * 异常类也是我自己定义的,可以根据自己的实际情况进行修改
 */
@Slf4j
@Component
public class TokenInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private JwtUtils jwtUtils;
    @Autowired
    private RedisUtil redisUtil;

    // 重写 前置拦截方法
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 从请求头中获取token
        String token = request.getHeader("token");
        log.info("开始拦截token:" + token);
        // 判断 token 是否存在
        if (token == null || "".equals(token)) {
            log.info("未登录的状态,直接跳转到登录前台页面");

            /*未登录的话需要跳转到管理端登录页面*/
            response.sendRedirect("http://www.baidu.com");

            // 这里可以自定义 抛出 token 异常
            throw new BusinessException(ResponseEnum.NOT_LOGGED_IN);
        }

        // 解析token
        Claims claim = jwtUtils.getClaimsByToken(token);

        if (StringUtils.checkValNull(claim)) {
            log.info("token 解析错误,直接跳转到登录前台页面");
            /*未登录的话需要跳转到管理端登录页面*/
            response.sendRedirect("http://www.baidu.com");
            // 这里可以自定义 抛出 token 异常
            throw new BusinessException(ResponseEnum.PARAM_ERROR);
        }

        // 判断 token 是否过期
        Date expiration = claim.getExpiration();
        boolean tokenExpired = jwtUtils.isTokenExpired(expiration);
        if (tokenExpired) {
            log.info("token已过期,直接跳转到登录前台页面");
            /*未登录的话需要跳转到管理端登录页面*/
           response.sendRedirect("http://www.baidu.com");
            // 这里可以自定义 抛出 token 异常
            throw new BusinessException(ResponseEnum.TOKEN_STALE_DATED);
        }

        // 从 token 中获取员工信息 ,严谨点的话应该去数据库里面查,但是有损性能就不做了
        String userId = claim.getSubject();
        if (StringUtils.isBlank(userId)) {
            log.info("校验这个token的真实性");
            /*未登录的话需要跳转到管理端登录页面*/
           response.sendRedirect("http://www.baidu.com");
            // 这里可以自定义 抛出 token 异常
            throw new BusinessException(ResponseEnum.PARAM_ERROR);
        }

        /**
         * 前提是,登录成功后生成token的时候,需要存放在redis 中一份
         * 根据userId和业务前缀组成的key,去redis中查询是否有对应的值
         * 1.存在,证明可以登录
         * 2.不存在,证明用户点了注销登录或者修改了密码,但是这个token还没有过期,请求中还在使用之前的token,这个时候应该让用户重新登录,并且在redis中将这个token删除
         */
        // 根据userId去redis中校验一下token是否已经修改了
		//  commonConfig.getLogin_token() 是我自己写的redis前缀,您可以根据自己的实际情况进行修改
        String redisToken = (String) redisUtil.get(commonConfig.getLogin_token() + userId);
        if (StringUtils.isBlank(redisToken) || !token.equals(redisToken)) {
            log.info("token不合格");
            /*未登录的话需要跳转到管理端登录页面*/
            response.sendRedirect(commonConfig.getWeb_login_url());
            // 这里可以自定义 抛出 token 异常
            throw new BusinessException(ResponseEnum.PARAM_ERROR);
        }
        return true;
    }
}

四: 配置拦截器,去做统一管理

package com.lemon.move.interceptor;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
/**
 * 设置拦截器.
 * 打上configuration 注解,标注为配置项
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
 
  // 注入 token 拦截器
  @Autowired
  private TokenInterceptor interceptor;
 
  /**
   * 重写添加拦截器
   */
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // 添加自定义拦截器,并拦截对应 url
    registry.addInterceptor(interceptor).addPathPatterns("项目路径")
            .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**")  //放行swagger路径
            .excludePathPatterns("/move/api/login/**"); // 放行其他路径
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lemon20120331

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值