1.什么是JWT
JWT官方的定义是:JSON Web令牌(JWT)是一个开放标准(RFC 7519),用于作为JSON对象在各方之间安全地传输信息。 可以验证和信任该信息,因为它是数字签名的。 jwt可以使用一个秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。
其实他本质上就是一个签名
,用于验证用户是否可以请求受限资源
(例如在商城中向服务器请求个人中心页面信息、购物车页面信息)
比如说现在在你家楼下有一家有一家自助餐厅,自助餐厅的门前有一个收银柜台。到了中午你感觉到肚子饿了,去了自助餐厅吃饭,去收银柜台交了钱,收银柜台给你开了一张你交过钱的证明,该证明里写了你什么时候交的钱,交了多少钱等信息,现在你拿着这张证明去餐厅里面吃饭,吃饭时候只要给这张证明就行,因为他认证了你的信息,店员知道你交过钱了也不会让你再交一次,同时防止了你不交钱吃饭的情况。
在这个例子中,我们如果把场景转换到网上商城(前后端分离的情况),收银柜台就是登录,登录完后服务器给你一个证明,证明你登录过了,这个证明有生成的时间、你的信息等等,这时候你想访问购物车,就拿着这个证明发给服务器,服务器验证该证明,验证通过后返回给你想要的数据。
还有一种情况就是如果你没有登录,想直接访问购物车的数据,服务器会发现你没有token(或者你伪造了一个token服务器验证不通过或者token过期),就会让你重新登录,从而实现了拦截访问受限资源的功能。
2.JWT生成token
2.1 添加依赖
1
2
3
4
5
6
7
8
9
10
|
< 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时候需要使用
1
2
3
4
5
6
7
|
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即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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为封装的返回对象,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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; } |
1
2
3
4
5
|
public class ResStatus { public static Integer OK = 10000 ; public static Integer NO = 10001 ; public static Integer PASS = 20002 ; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
@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开头请求负责登录和注册不应被拦截
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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/**" ); } } |
到此这篇关于SpringBoot-JWT生成Token和拦截器的使用(访问受限资源)的文章就介绍到这了,更多相关SpringBoot-JWT生成Token和拦截器内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://juejin.cn/post/7095247718490046472