JWT令牌检验用户是否登录
JWT是一种解决分布式系统中用户认证问题的令牌机制。它由Header、Payload和Signature三部分组成,通过Base64Url编码和服务器密钥签名确保数据完整性。相比session存储在服务器内存的方式,JWT更适合分布式环境。实现步骤包括:引入jjwt依赖、配置密钥、生成token、解析token数据、登录后发放token给前端,并通过拦截器验证请求中的token有效性。JWT虽然解
文章目录
JWT检验用户是否登录
由于session存储在服务器内存中,集群和分布式的存在使session无法在不同机器中共同使用,因此session中不适合存用户个人信息
JWT介绍
JWT官网
JWT (JSON WEB TOKEN)是一种以令牌传输的信息传递方式,类似于一张医院就诊卡,包含了用户的全部信息.
JWT由三部分组成:
1. Header(头部),声明了使用的算法
2. Payload(载荷),传输的数据内容
3. Signature(签名),让服务器校验这个令牌是没有被别人修改的,不被伪造的(签名部分是和前两部分结合放伪的)
JWT 将头部和载荷部分进行Base64Url编码(编码解码都是公开的,这里面的数据是不保密的),拼接字符串,然后将前两部分和服务器独有的秘钥加进算法中生成签名,这三部分通过编码以字符串token的形式,在客户端暂存.
A + B = C
一旦A(数据)被改变,B永远在服务器当中不可改变,那么C就不同,就能知道A是被篡改过的,不是自身服务器生成的.
当然,JWT本身是解决集群和分布式的问题.用户数据信息本身就不在JWT中被加密保护,对用户信息保密需要采用其他的安全手段
JWT使用
1. 引入依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- 或 jjwt-gson -->
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
2. 生成token
生成token之前,先配置一下秘钥
- 秘钥Key由一串字符串封装而成 ,这个字符串有长度的要求以确保不被破解,我们更推荐直接让系统生成符合对应算法的字符串
- SecretKey继承了Key这个父类,Key是非对称加密,SercretKey是对称加密,方便解密拿到数据内容.
- secretKey本质是字符串,可以互相转变,为了以后能够用这个secretKey解密拿数据,我们把它的字符串存下来,这个字符串就作为每一次生成和解密的秘钥;
//private static final String str1 = "sjdad789fdsdja9s8djsf90a";//自己写一个字符串
//private static final SecretKey key1 = Keys.hmacShaKeyFor(Decoders.BASE64.decode(str1));//通过这个字符串构建key
//更推荐使用系统帮我们生成SecretKey,一次使用,终身受益
SecretKey secretKey1 = Keys.secretKeyFor(SignatureAlgorithm.HS256);//参数指定加密算法
//将这个秘钥转换回字符串,建议打印出这个字符串保存为常量
String keyString = Encoders.BASE64.encode(secretKey1.getEncoded());
private static final SecretKey secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(keyString));//通过这个字符串构建key
另外
- token可以配置签发时间和过期时间;
- 传入的数据Claims继承Map<String,Object>
public interface Claims extends Map<String, Object>, Identifiable {-----}
private static final long JWT_EXPIRATION = 60*60*1000;//配置过期的时长
public static String genJwtToken(Map<String, Object> claim){
Date now = new Date();
String token = Jwts.builder()//得到一个构造器
.claims(claim) //需要传入一个map数据
.issuedAt(now) // 当前签发时间
.expiration(new Date(now.getTime() + JWT_EXPIRATION)) // 过期时间
.signWith(secretKey1) // 使用密钥签名
.compact();//将上面的配置结合
return token;
}
3. 通过token拿取数据
public static Claims parseToken(String token){
Claims claims = null;
try {
claims = Jwts.parser()
.verifyWith(sercretkey) // 使用同一密钥验签
.build() //通过秘钥生成解析器
.parseSignedClaims(token) // 验签并解析
.getPayload(); //拿到token第二部分里的数据
}catch (Exception e){
log.error("解析token失败, token:{}", token);
return null;
}
return claims;
}
4. 登录之后发放token
public Result login(String userName, String password){
//-------------
//在一系列的登录校验之后成功登录,发放token
Map<String,Object> userInfoMap = new HashMap<>();
//token里可以放一些用户的基本信息,比如id和用户名,不建议放敏感信息
userInfoMap.put("id",userInfo.getId());
userInfoMap.put("userName",userInfo.getUserName());
String token= JwtUtils.genJwtToken(userInfoMap);
return Result.success(token);
}
将token发给前端,前端将token保存到cookie上,后续每一次请求都发送token.
5. 配置拦截器拦截前逻辑
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//处理拦截之前的逻辑
//如果客户端是将token放在请求头中的
String token = request.getHeader("user_token_header");//这个字符串是前端设置的主键,内容是token
log.info("正在验证token,token->{}", token);
if(JwtUtils.parseToken(token) == null){
log.info("token无效,请重新登录");
response.setStatus(401);//未授权
return false;
}
return true;
}
}
6.添加拦截器到spring
@Configuration //注入拦截器到spring容器
public class LoginConfig implements WebMvcConfigurer {
@Autowired
LoginInterceptor loginInterceptor;
private List<String> list = Arrays.asList(
"/user/login",
"/user/register",
"/**/*.html",
"/css/**",
"/js/**",
"/pic/**",
"/blog-editormd/**",
"/favicon.ico"
);
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加拦截器
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**") //拦截所有请求
.excludePathPatterns(list); //传入一个list统计需要排除的接口
}
}
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)