Jwt
说明
观看B站视频整理的笔记。https://www.bilibili.com/video/BV1i54y1m7cP?from=search&seid=11707701064126824134
JTW的简介和传统认证流程对比
什么是JWT?
JWT官网地址:https://jwt.io/introduction
JWT的全称:JSON Web Token,即json格式网站令牌
Jwt的作用
1.授权
这是使用JWt的最常见的方案,一旦用户登录,每个后续请求将包括JWT,从而允许用户访问该令牌允许的路由、服务和资源。单点登录是当今广泛使用JWT的一项功能,因为它的开销很小并且可以在不同的域中轻松使用。
2.信息交换
JWT是在各方之间安全地传输信息的好方法。因为可以对JWt进行签名(例如:使用公钥/私钥对),所以可以确保发件人是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此还可以验证内容是否遭到篡改。
为什么使用JWT
基于传统的Session认证
基于JWT认证
JWT的结构
使用JWT
封装工具类
springboot整合JWT
整体流程:前台发送用户名、密码---->后台验证是否成功,成功则生成Token返回令牌。
注意:令牌的盐值必须4个及以上字符否则会出现如下错误:
jwt工具类
package com.example.jwt.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @Author czf
* @Date 2021/3/23
* @ClassName: JwtUtil
* @Description: jwt的工具类
* @Version 1.0
*/
@Component
public class JwtUtil {
// 盐值
private static final String KEY = "czfs";
//一天时间失效
private static final String ttl = "86400000";
/**
* 签发 生成 token
*/
public static String createJWT(String userId, String userName) {
long now = System.currentTimeMillis();
long time = Long.parseLong(ttl);
long exp = now + time;
//1.创建jwtBuilder
JwtBuilder jwtBuilder = Jwts.builder().setId(userId)
.setSubject(userName).setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, KEY);
//时间设置
if (time > 0) {
jwtBuilder.setExpiration(new Date(exp));
}
return jwtBuilder.compact();
}
/**
* 解析 token
*/
public static Claims parserJWT(String token) {
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(KEY)
.parseClaimsJws(token).getBody();
} catch (Exception ignored) {
}
return claims;
}
}
拦截器
package com.example.jwt.configure;
import com.alibaba.fastjson.JSONObject;
import com.example.jwt.util.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
* @Author czf
* @Date 2021/3/23
* @ClassName: JwtInterceptor
* @Description: 对请求进行token的验签
* @Version 1.0
*/
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
Claims claims = JwtUtil.parserJWT(token);
if (claims == null){
log.info("token不正确!");
Map<String, Object> map = new HashMap<>();
map.put("msg", "token不正确");
// 将map转换为json ,response底层有jackson
/* String jsonString = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=utf-8");
response.getWriter().println(jsonString);*/
// fastJson将map转换json字符串
JSONObject jsonObject = new JSONObject(map);
String jsonString = jsonObject.toString();
response.setContentType("application/json;charset=utf-8");
response.getWriter().println(jsonString);
return false;
}
return true;
}
}
注册拦截器
package com.example.jwt.configure;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author czf
* @Date 2021/3/23
* @ClassName: InterceptorConfig
* @Description: 拦截器的配置信息
* @Version 1.0
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 除了登录请求不需要验签,其它请求都需要
registry.addInterceptor(new JwtInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/user/login");
}
}
基类控制层
package com.example.jwt.controller;
import com.example.jwt.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.web.bind.annotation.ModelAttribute;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author czf
* @Date 2021/3/23
* @ClassName: BaseController
* @Description: 抽取控制层的公共代码
* @Version 1.0
*/
public class BaseController {
protected HttpServletRequest request;
protected HttpServletResponse response;
protected String userName;
protected String token;
protected String userId;
@ModelAttribute
public void setResAnReq(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
try {
this.token = this.request.getHeader("token");
Claims claims = JwtUtil.parserJWT(token);
this.userName = claims.getSubject();
this.userId = claims.getId();
} catch (Exception e) {
System.out.println("令牌不正确!");
throw e;
}
}
public String getUserName(){
return this.userName;
}
}
@ModelAttribute注解的作用
被@ModelAttribute注释的方法会在此controller每个方法执行前被执行。所以setResAnReq
方法会在这个controller中优先执行。
controller
package com.example.jwt.controller;
import com.example.jwt.modol.User;
import com.example.jwt.service.impl.UserServiceImpl;
import com.example.jwt.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* @Author czf
* @Date 2021/3/23
* @ClassName: userController
* @Description: 用户控制层
* @Version 1.0
*/
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController extends BaseController{
@Resource
UserServiceImpl userServiceImpl;
@PostMapping("/login")
public String login(@RequestParam String userName,@RequestParam String password){
User user1 = userServiceImpl.findUser(userName,password);
if (null !=user1){
String token = JwtUtil.createJWT("" + user1.getId(), user1.getUserName());
return token;
}else {
return "fail";
}
}
@GetMapping("/test")
public String test(){
log.info("用户名:{}" ,getUserName());
return "test";
}
}
代码托管:https://gitee.com/czf96/jwt
JWt与sesion的对比
JWt是存储在客户端中的,而sesion存储在服务器内存中。如果将后台关闭过,sesion就失效(丢失)了必须重新登录验证。JWt只要token没有过期(无论后台是否关闭过),都可以直接使用,后台对token进行验证,验证(验证token是否是自己创建的)通过就可以访问控制层了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)