SpringBoot-JWT生成Token和拦截器

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

SpringBoot-JWT生成Token和拦截器

七旅之言   2022-06-03 我要评论

1.什么是JWT

JWT官方的定义是:JSON Web令牌(JWT)是一个开放标准(RFC 7519),用于作为JSON对象在各方之间安全地传输信息。 可以验证和信任该信息,因为它是数字签名的。 jwt可以使用一个秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。

其实他本质上就是一个签名,用于验证用户是否可以请求受限资源(例如在商城中向服务器请求个人中心页面信息、购物车页面信息)

比如说现在在你家楼下有一家有一家自助餐厅,自助餐厅的门前有一个收银柜台。到了中午你感觉到肚子饿了,去了自助餐厅吃饭,去收银柜台交了钱,收银柜台给你开了一张你交过钱的证明,该证明里写了你什么时候交的钱,交了多少钱等信息,现在你拿着这张证明去餐厅里面吃饭,吃饭时候只要给这张证明就行,因为他认证了你的信息,店员知道你交过钱了也不会让你再交一次,同时防止了你不交钱吃饭的情况。

在这个例子中,我们如果把场景转换到网上商城(前后端分离的情况),收银柜台就是登录,登录完后服务器给你一个证明,证明你登录过了,这个证明有生成的时间、你的信息等等,这时候你想访问购物车,就拿着这个证明发给服务器,服务器验证该证明,验证通过后返回给你想要的数据。

还有一种情况就是如果你没有登录,想直接访问购物车的数据,服务器会发现你没有token(或者你伪造了一个token服务器验证不通过或者token过期),就会让你重新登录,从而实现了拦截访问受限资源的功能。

2.JWT生成token

2.1 添加依赖

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.3</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

2.2 生成token

该案例为 在 登录的Controller中,用户的账号密码输入正确,生成token,其中最重要的是token的密码,验证token时候需要使用

JwtBuilder builder = Jwts.builder();
String token = builder.setSubject("userName")
        .setIssuedAt(new Date()) //设置token生成时间
        .setId(u.getUserId() + "")//设置tokenID
        .setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000))//设置过期时间,现在为设置 一天
        .signWith(SignatureAlgorithm.HS256, "123456")//设置token密码,解析token需要使用
        .compact();

到此token生成完毕,接着返回给前端,前端收到后将其存在cookie当中 这里提供一个设置cookie的工具类代码,设置或者取出cookie可以直接使用 每次前端发送请求时候都在 请求头 中携带token即可

var operator = "=";

//取出cookie
function getCookieValue(keyStr){
	var value = null;
	var s = window.document.cookie;
	var arr = s.split("; ");
	for(var i=0; i<arr.length; i++){
		var str = arr[i];
		var k = str.split(operator)[0];
		var v = str.split(operator)[1];
		if(k == keyStr){
			value = v;
			break;
		}
	}
	return value;
}
//设置cookie
function setCookieValue(key,value){
	document.cookie = key+operator+value;
}

2.3 使用拦截器解析token

配置拦截器

其中ResultVO和ResStatus为封装的返回对象,代码如下:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultVO {
    @ApiModelProperty("响应状态码")
    private Integer code;
    @ApiModelProperty("响应信息")
    private String msg;
    @ApiModelProperty("响应数据")
    private Object Data;
}
public class ResStatus {
    public static Integer OK = 10000;
    public static Integer NO = 10001;
    public static Integer PASS = 20002;
}
@Component
public class CheckTokenInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    //因为是在请求头中发送token,所以第一次请求的方法为"OPTIONS",具体可以看TCP/IP协议
        String method = request.getMethod();
        if("OPTIONS".equalsIgnoreCase(method)){
            return true;
        }
        String token = request.getHeader("token");
        System.out.println("token:"+token);
        if(token == null){
            ResultVO resultVO = new ResultVO(ResStatus.NO,"请先登录",null);
            doResponse(response,resultVO);
        }else{
            try{
                //在jwt中,只要token不合法或者验证不通过就会抛出异常
                JwtParser parser = Jwts.parser();
                parser.setSigningKey("123456");
                Jws<Claims> claimsJws = parser.parseClaimsJws(token);
                return true;
            }catch (ExpiredJwtException e1) {
                ResultVO resultVO = new ResultVO(ResStatus.PASS, "登录过期,请重新登录", null);
                doResponse(response,resultVO);
            }catch (UnsupportedJwtException e2){
                ResultVO resultVO = new ResultVO(ResStatus.NO, "Token不合法,已记录恶意IP", null);
                doResponse(response,resultVO);
            }catch (Exception e3){
                ResultVO resultVO = new ResultVO(ResStatus.NO, "请先登录", null);
                doResponse(response,resultVO);
            }
        }
        return false;
    }

    @SneakyThrows
    private void doResponse(HttpServletResponse response, ResultVO resultVO) {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        String s = new ObjectMapper().writeValueAsString(resultVO);
        out.print(s);
        out.flush();
        out.close();
    }
}

设置拦截器拦截的内容

拦截了shopcart的请求,排除了user开头的请求,因为user开头请求负责登录和注册不应被拦截

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;
import javax.annotation.Resource;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Resource
    private CheckTokenInterceptor checkTokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(checkTokenInterceptor)
                .addPathPatterns("/shopcart/**")
                .excludePathPatterns("/user/**");
    }
}

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们