当前位置: 首页 > news >正文

Threadlocal+拦截器+JWT实现登录

很多数据库表都会有创建时间和修改时间,这个可以用mp的自动填充来实现。

也有修改人和更新人的字段,用户登录进来后,修改数据如何拿到修改人呢?每次操作不能把操作人的信息都携带者,那么如何拿到修改人的数据,主要是需要拿到id。

JWT

http协议本身是一种无状态的协议,如果用户向服务器提供了用户名和密码来进行用户认证,下次请求时,用户还要再一次进行用户认证才行。因为根据http协议,服务器并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储─份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样应用就能识别请求来自哪个用户

JWT JSON Web Token(JSON Web令牌)
是一个开放标准(rfc7519),它定义了一种紧凑的、自包含的方式,用于在各方之间以JSON对象安全地传输信息。此信息可以验证和信任,因为它是数字签名的。jwt可以使用秘密〈使用HNAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。

JWT作用:
授权:一旦用户登录,每个后续请求将包括JWT,从而允许用户访问该令牌允许的路由,服务和资源。它的开销很小并且可以在不同的域中使用。如:单点登录。
信息交换:在各方之间安全地传输信息。JWT可进行签名(如使用公钥/私钥对),因此可确保发件人。由于签名是使用标头和有效负载计算的,因此还可验证内容是否被篡改。

image.png
image.png

后端将token传给前端的时候,放入了id进去。前端再次访问的时候可以拿到用户的id。后端通过拦截器拦截。

JWT封装成工具类

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;public class JwtUtil {//将密钥 和数据加密生产token//创建token 三个参数   密钥  过期时间   需要保存的数据public static String createJWT(String secretKey, long ttlMills, Map<String, Object> claims) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;long expMills = System.currentTimeMillis() + ttlMills; //存储时间Date exp = new Date(expMills); //时间转为dateJwtBuilder builder = Jwts.builder().setClaims(claims)  //载荷.signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8)).setExpiration(exp); //过期时间return builder.compact(); // 变为字符串}/*根据token解析得到里面的数据*/public static Claims parseJWT(String secretKey, String token) {try {Claims claims = Jwts.parser().setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8)).parseClaimsJws(token).getBody();return claims;}catch (Exception e){throw new RuntimeException("token失效");}}
}

密钥和时间配置存在application.yml文件中

@Data
@Component
@ConfigurationProperties(prefix = "shop.jwt")
public class JwtProperties {private String secret; // 密钥private int expire; // 过期时间(分钟)
}
shop:jwt:secret: njitzxexpire: 60480000

拦截器

拦截器是SpringMVC下面的。

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {//添加拦截器registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/captchaLogin","/captchaImage", "/login","/alipay/notify");}
}
通过实现 WebMvcConfigurer 接口配置 Spring MVC。
将 LoginInterceptor 添加到拦截器注册表中,使其拦截所有进入的请求,
除了那些在 excludePathPatterns 中指定的路径(如登录接口、验证码接口等)。
package com.njitzx.interceptor;import com.njitzx.exception.LoginErrorException;
import com.njitzx.properties.JwtProperties;
import com.njitzx.util.BaseContext;
import com.njitzx.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
@RestController                        //实现拦截器的接口
public class LoginInterceptor implements HandlerInterceptor {//请求之前拦截@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("进行登录拦截器");//if (!(handler instanceof HandlerMethod)){return  true;}简单来说,这个条件检查确保了只有那些由控制器方法(HandlerMethod)处理的请求才会被拦截器进一步处理。对于静态资源、错误页面、自定义处理器等非控制器方法处理的请求,拦截器会自动放行,不进行额外的拦截操作。String token = request.getHeader("Authorization"); //从请求头中拿到tokentry {Claims claims = JwtUtil.parseJWT("njitzx", token);Integer id = claims.get("id", Integer.class);BaseContext.setCurrentId(id); System.out.println("用户的id" + id);return true;}catch (Exception ex){//如果返回 直接返回401response.setStatus(401);return  false;}}
}
  • 实现了 HandlerInterceptor 接口,重点实现了 preHandle 方法。
  • preHandle 方法会检查请求头中是否有一个有效的 JWT。
  • 如果 token 有效,会提取用户的 ID 并存储到 BaseContext 中以供后续使用。
  • 如果 token 无效或缺失,则将响应状态设置为 401 Unauthorized,并阻止请求继续处理。

Threadlocal

ThreadLocal叫做_线程变量,意思是ThreadLocal中填充的变量_属于**当前线程**,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

每个用户进来之后的threadLocal存储的值都是不一样的,具有隔离的特性。

public class BaseContext {private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();public static void setCurrentId(Integer id) {threadLocal.set(id);}public static Integer getCurrentId() {return threadLocal.get();}public static void removeCurrentId() {threadLocal.remove();}
}

在拦截器那边通过token拿到id,并存入到threadlocal

Integer id = claims.get("id", Integer.class);
BaseContext.setCurrentId(id); 

登进系统之后需要根据根据不同的人显示不同的菜单,如何表示当前的用户呢,请求的时候走拦截器可以拿到id。
image.png


http://www.mrgr.cn/news/12571.html

相关文章:

  • 【Docker项目实战】使用Docker部署webtop桌面版Linux环境
  • 华为手机数据丢失如何恢复?
  • golang本地缓存fastcache高性能实现原理
  • sqlite3 在Python中使用
  • 筑牢技术防线:服务器故障后的应急响应与未来防范策略
  • 2024年8月22日嵌入式学习
  • Linux——文件系统层次结构,绝对路径
  • 视频提取字幕的软件有哪些?5款高识别率工具任你选
  • SpringBoot文档之构建包的阅读笔记
  • spring security怎么解决用户的权限问题
  • SAP 有趣的‘bug‘ 选择屏幕输入框没了
  • 小白之 FastGPT Windows 本地化部署
  • Linux内核定时器
  • 5G SSB(Synchronization Signal/PBCH, 同步广播块
  • HarmonyOs应用权限申请,system_grant和user_grant区别。本文附头像上传申请user-grant权限代码示例
  • C HTML格式解析与生成
  • 深度学习学习经验——深度学习名词字典
  • [Meachines] [Easy] jerry Tomcat用户暴力破解+war包webshell上传
  • 腾讯地图接入报错vue.runtime.esm.js:4605[Vue warn]: Error in v-on handler: “far <= 0“
  • 基于单片机的无线空气质量检测系统设计