目录
需要解决的问题:用户在未登录状态下,也可以通过访问网址直接跳过登录界面

通过登录成功的标记来检测,在每个接口前做一个标记判断是否登录,若没登录则返回错误信息,并使前端退出

但这样较为繁琐,因此我们可以通过一种统一拦截的技术来拦截所有请求.这涉及到了会话跟踪这一技术.




跨域:只要协议/IP地址/端口三个维度任何一个不同,就是跨域操作


一个令牌包含三个部分:头/有效载荷/签名:防止令牌被篡改

核心的两个步骤:
生成令牌 & 校验令牌

第一步--生成令牌
1.签名算法
2.自定义内容
3.令牌有效期

以下为测试样例:
- @Test
- public void JwtTest()
- {
- Map
claims = new HashMap<>(); - claims.put("id", 1);
- claims.put("name", "tom");
- /*此处负载的内容是id和姓名*/
- String jwt = Jwts.builder()
- /*设置签名算法*/
- .signWith(SignatureAlgorithm.HS256, "theresa")
- /*自定义内容(负载)*/
- .setClaims(claims)
- /*设置有效期为一小时*/
- .setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))
- .compact();
-
- }
报错的两种情况:过期/被篡改
.setSigningKey("")填入和开始输入的一样,签名算法
.parseClaimsJws("")中填入要校验的令牌
- public void ParseJwt(String jwt){
- //许可验证
- Claims claims = Jwts.parser()
- .setSigningKey(signKey)//传递签名
- .parseClaimsJws(jwt)//传递令牌
- .getBody();//得到内容
- System.out.println(claims);
-
- }
- @PostMapping("/login")
- public Result login(@RequestBody Emp emp){
-
- log.info("员工登录:{}",emp);
- Emp e = empService.login(emp);
-
- //若登录成功,生成令牌并下发令牌
- if(e != null)
- {
- //定义claims携带当前登录的员工信息
- Map
claims = new HashMap<>(); - claims.put("id",e.getId());
- claims.put("name",e.getName());
- claims.put("username",e.getUsername());
-
- //此处将claims传入了我们第一步定义的生成令牌工具类中
- String jwt = JwtUtils.generateJwt(claims);
-
- return Result.success(jwt);
- }
-
- //若登录失败,返回错误信息
- return Result.error("用户名或密码错误");
- }
- }
ThreadLocal不是一个Thread,而是Thread的局部变量
ThreadLocal为每个线程单独提供一个存储空间,具有线程隔离效果,只有在线程内才能获取到对应的值,线程外则不能访问。
客户端每一次访问,tomacat都会开辟一个线程
所以当我们保证在线程的生命周期只内,能访问到,就可以把值放到里面。
解决原理
代码中已经提供了封装好的ThreadLocal,名字是BaseContext, 因为每次请求都会用开辟一个线程,而且每次请求前端都会带token过来,所以它发送保存用户的时候也会带token过来进行验证.
所以将jwt验证出来的token放置在ThreadLocal中
因为这次保存和他是一个线程,所以ThreadLocal还是一个,所以保存的时候直接从ThreadLocal中获取即可
解决方式
在jwt验证的代码中放置token到ThreadLocal
在service中获取ThreadLocal将id放进去验证