JWT代码实现

news/2025/3/4 5:17:14/

什么是 JWT?

JSON Web Token,通过数字签名的方式,以 JSON 对象为载体,在不同的服务终端之间安全的传输信 息。(将信息进行封装,以 JSON 的形式传递) JWT 有什么用? JWT 最常见的场景就是授权认证,一旦用户登录,后续每个请求都将包含 JWT,系统在每次处理用户请 求的之前,都要先进行 JWT 安全校验,通过之后再进行处理。

前后端传输数据时,一般是使用 session 或是 cookie,但是都相对有自己的弊端,JWT 是利用 token 来对用户身份进行验证的方式,具体流程是前端使用用户名和密码来登录,服务器收到请求后验 证用户名和密码,验证成功后,服务器会签发一个 token ,将 token 返回给前端,前端将收到的 token 存储起来,在每次请求资源时都必须携带 token,服务器收到请求,会先验证 token 是否有效,验证成 功就给前端返回请求的数据。

优势

这种基于 token 的认证方式相对于传统的 session 认证方式更节约服务器资源,token 在服务端不需要 存储 session 信息,因为 token 自身包含了所有登录用户的信息,所有可以减轻服务端压力。

JWT 的组成 JWT 由 3 部分组成,用.拼接

eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiI
sInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2NjU1NTAzNDIsImp0aSI6IjBiOWU3MmRmLTQ0NjQtNDV
kYy04ODMwLWU3NTJkMjg1OGQ0MCJ9.00-RQiPM_a9_0q03CrmcrOBMaLbcfWw85Mbc7xc4AtU

 这三部分分别是:

Header

包含token 类型和加密算法的名称

{
//类型
'typ': 'jwt',
//算法
'alg': 'HS256'
}

将信息进行base64编码(转码)

Payload //载荷(存储有效信息)

包含标准中注册的声明、公共的声明、私有的声明,其实就是信息安全的分类,存储主要的信息 同时也需要将信息进行base64编码(转码) 

{
"sub": '1234567890',
"name": 'john',
"amdin":true
}

Signature //签名

将转码后的 header 和 payload 用.进行拼接之后再用使用 HS256 进行加盐加密,就构成了 jwt 的第三 部分

其实就是由转码后的 header 和 payload 进行再次加密后的数据

//对转码后的 Header 和 Payload 用.进行拼接
var encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload);
//使用 HS256 进行加盐加密
var signature = HMACSHA256(encodedString, 'secret');

项目搭建

pom.xml

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- jdk1.8 以上要加-->
<!-- <dependency>-->
<!-- <groupId>javax.xml.bind</groupId>-->
<!-- <artifactId>jaxb-api</artifactId>-->
<!-- <version>2.3.1</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>com.sun.xml.bind</groupId>-->
<!-- <artifactId>jaxb-impl</artifactId>-->
<!-- <version>2.3.0</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>com.sun.xml.bind</groupId>-->
<!-- <artifactId>jaxb-core</artifactId>-->
<!-- <version>4.0.1</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>javax.activation</groupId>-->
<!-- <artifactId>activation</artifactId>-->
<!-- <version>1.1</version>-->
<!-- </dependency>-->

测试加密/解密

如何使用 jwt

加密

在这里我们测试一下 jwt 的加密和解密过程来了解 jwt

首先使用 JwtBuilder 来创建 jwt 对象 ,根据三部分先加入 jwt 的 header,使用.setHeaderParam() 这里使用链式编程增加参数,再加入载荷 payload 使用 .claim() 方法 还可以加入主题和有效时间(一 天的有效时间 System.currentTimeMillis() + time),id 用了 UUID

定义全局签名信息用于解密,使用 .sigWith(算法,签名key) 加密,调用 .compact() 进行拼接

输出 JWT 数据

import io.jsonwebtoken.*;
import javafx.scene.chart.PieChart;
import sun.awt.SunHints;
import java.security.Key;
import java.security.KeyException;
import java.util.Date;
import java.util.UUID;
public class Test {
private long time = 1000*60*60*24;
private String signature = "amdin";//签名信息(解密)
@org.junit.Test
public void jwt(){
JwtBuilder jwtBuilder = Jwts.builder();//用来构建jwt对象
String jwtToken = jwtBuilder
//Header
.setHeaderParam("typ","jwt")
.setHeaderParam("alg","HS256")
//Payload
.claim("username","tom")
.claim("role","admin")
.setSubject("admin-test")//主题
.setExpiration(new Date(System.currentTimeMillis() + time))//有效
时间 当前时间+一天 24h
.setId(UUID.randomUUID().toString())
//Signature
.signWith(SignatureAlgorithm.HS256,signature)
.compact();//拼接三部分
System.out.println(jwtToken);
}
@org.junit.Test
public void parse(){
String token =
"eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbi
IsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2NjU1NTAzNDIsImp0aSI6IjBiOWU3MmRmLTQ0NjQtND
VkYy04ODMwLWU3NTJkMjg1OGQ0MCJ9.00-RQiPM_a9_0q03CrmcrOBMaLbcfWw85Mbc7xc4AtU";
JwtParser jwtParser = Jwts.parser();
//解密 通过签名进行解析
Jws<Claims> claimsJws =
jwtParser.setSigningKey(signature).parseClaimsJws(token);
//把解析的数据存入对象中
Claims claims = claimsJws.getBody();
//从对象中取出数据
System.out.println(claims.get("username"));
System.out.println(claims.get("role"));
System.out.println(claims.getId()); //ID
System.out.println(claims.getSubject()); //签名
System.out.println(claims.getExpiration()); //有效期截至时间
}
}

对 token 进行解密

首先 使用 Jwts.parser() 对象的 .setSigningkey(签名key)解密 .parseClaimsJws(token)会把所有信息解 析成 Claims,Claims 相当于我们的各种数据,通过签名对 token 进行解析拿到 Claims ,调用 .getBody 方法把封装的数据放到 claims 对象当中,之后就可以使用 对象 .get 方法取出数据,从而将 jwttoken 中解析出我们的数据。

Spring boot + vue + Jwt

简单的小项目来了解 jwt 具体用法

作为java web中的一个令牌,就像之前测试加密时,用户在登录后,访问咱们的登录接口,登录接口判 断登录成功后把用户信息转为 jwtoken(jwt工具类,跟上面加密过程一样) 存入用户信息中,把整个 用户对象给到前端。

controller

@GetMapping("/login")
public User login(User user){
if (USERNAME.equals(user.getUsername()) &&
PASSWORD.equals(user.getPassword())){
//添加token
user.setToken(JwtUtil.createToken());
return user;
}
return null;
}

 JwtUtil

private static long time = 1000*60*60*24;
private static String signature = "amdin";
public static String createToken(){
JwtBuilder jwtBuilder = Jwts.builder();//用来构建jwt对象
String jwtToken = jwtBuilder
//Header
.setHeaderParam("typ","jwt")
.setHeaderParam("alg","HS256")
//Payload
.claim("username","admin")
.claim("role","admin")
.setSubject("admin-test")//签名
.setExpiration(new Date(System.currentTimeMillis() + time))//有效
时间 当前时间+一天 24h
.setId(UUID.randomUUID().toString())
//Signature
.signWith(SignatureAlgorithm.HS256,signature)
.compact();//拼接三部分
return jwtToken;
}

 前端拿到数据,从请求中拿到 JSON 进入 home 页面

this.$refs.loginForm.validate((valid) => {
if (valid) {
//点击登录后的一个入口
// alert('submit!');
//把全局this记录下来
let _this = this
//axios的get请求需要套{params:_this},需要把loginForm对象给到
后台
this.$axios.get('http://localhost:8080/login',
{params:_this.loginForm}).then(function (response) {
console.log(response.data)
//使用 localStorage 进行存储 access-admin(localStorage
只能存储字符串)
localStorage.setItem('accessadmin',JSON.stringify(response.data))//JSON.stringify JSON转字符串的方法
//去到登录成功的页面
_this.$router.replace({path:'/home'})
})
} else {
this.$message.error('请输入所有字段!');
return false;
}
});

 登录后在请求中拿到用户数据(保证安全性不显示)

 home页面,将 JSON 取出并还原存入全局变量 admin 中,就可以从 admin 中取出数据显示到页面上

 

 

created() {
this.admin = JSON.parse(window.localStorage.getItem('access-admin'))
}

登录成功后切换页面进行验证(因为每次跳转都需要向后台发请求,重复代码太多,把验证抽象出来, 实现代码复用,所以写到路由当中,每个页面的跳转都需要经过路由)俗称路由守卫,首先验证用户是 否登录,(取出 JSON 还原 判断)如果没有登录直接跳转到登录页面,接着检验token合法性,访问后 台/checkToken,把保存的 token 传到后台进行认证,后台返回布尔值,如果是 flase 提示校验失败跳 转到错误页面,正确直接往后运行

router.beforeEach((to,from,next)=>{
if (to.path.startsWith('/login')) {
window.localStorage.removeItem('access-admin')
next()
} else {
//验证是否登录
let admin = JSON.parse(window.localStorage.getItem('access-admin'))
if (!admin){
next({path:'/login'})
} else {
//校验token合法性
axios({
url:'http://localhost:8081/checkToken',
method:'get',
headers:{
token:admin.token//类似?传参
}
}).then((response)=>{
console.log(response.data)
//给一个布尔值,如果是flase,提示校验失败,给到错误页面
if (!response.data){
console.log('校验失败')
next({path:'/error'})
}
})
next()
}
}
})

后台验证

从 headers 中获取前端给的 token,进入工具类中进行验证

controller

@GetMapping("/checkToken")
public Boolean checkToken(HttpServletRequest request){
//因为前端是存入 headers 中
String token = request.getHeader("token");
return JwtUtil.checkToken(token);
}

判断 token 是否为空,使用 Jwts.parser()方法,类似之前的解密 token ,解析签名 signature ,解析后 拿到集合 获取 JwtToken ,不需要拿出数据,只需要判断解析是否异常,如果解析异常说明 token 失 效,如果有异常返回 false,反之则返回 true,给到前端

JwtUtil

public static boolean checkToken(String token){
if (token == null){
return false;
}
try {
//判断token是否有效,如果解析异常说明token无效
Jws<Claims> claimsJws =
Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
} catch (Exception e) {
return false;
}
return true;
}

 在前端 console.log(response.data) 中可以看出是否有效

 

 验证,改变 token 有效时间

private static long time = 1000*5;


http://www.ppmy.cn/news/362371.html

相关文章

苹果公司

苹果公司 求助编辑百科名片 Apple 苹果公司&#xff08;Apple Inc.&#xff09;是美国的一家高科技公司&#xff0c;2007年由苹果电脑公司&#xff08;Apple Computer, Inc.&#xff09;更名而来&#xff0c;核心业务为电子科技产品&#xff0c;总部位于加利福尼亚州的库比蒂诺…

苹果“慌了”,中国客户不买账,这次要提供“折扣”可谓罕见

今天&#xff0c;苹果中国官网推出iPhone 12、iPhone 13、Apple Watch、AirPods等产品的折扣。 据该网站称&#xff0c;iPhone 13系列为600元&#xff08;89美元&#xff09;折扣&#xff0c;iPhone 12和iPhone 12 mini为500元折扣&#xff0c;Apple Watch SE为200元折扣&#…

苹果官网下载

https://developer.apple.com/downloads/index.action 转载于:https://www.cnblogs.com/lihaibo-Leao/p/4466854.html

华为OD-2023B卷 -组成最大数(java)

4.华为OD-2023B卷 -组成最大数(回到目录) 难度:★ 了解(x+y) 和(y+x)比较大小的原理,会发现这道题很简单,包括类似组成最大最小的题,都可以用这个解法。 组成最大数 知识点排序 时间限制:1s 空间限制:64MB 限定语言:不限 题目描述: 小组中每位都有一张卡片,卡片…

项目管理专业人员能力评价(CSPM)含金量高吗?都考什么?

2021年10月&#xff0c;中共中央、国务院发布的《国家标准化发展纲要》明确提出构建多层次从业人员培养培训体系&#xff0c;开展专业人才培养培训和国家质量基础设施综合教育。建立健全人才的职业能力评价和激励机制。由中国标准化协会&#xff08;CAS&#xff09;组织开展的项…

2023年如何创建成功的海外社交内容日历

您是否厌倦了不断被社交媒体内容创建过程所淹没&#xff1f;是否厌倦了在最后一刻匆忙提出甚至无法吸引受众的点子&#xff1f;不要害怕&#xff0c;因为今天我们将讨论如何创建一个社交媒体内容日历&#xff0c;它将在2023年改变您的方法。 目录 什么是社交媒体内容日历&…

成功邀请媒体采访的关键步骤,媒介易助你成为媒体热门

在企业品牌推广和宣传中&#xff0c;与媒体建立合作关系&#xff0c;并邀请媒体进行采访是非常重要的环节。通过媒体的报道和宣传&#xff0c;企业可以扩大品牌的曝光度&#xff0c;提升品牌形象和知名度。然而&#xff0c;成功的媒体邀约并非易事&#xff0c;需要一定的策略和…

CCF python 门禁系统

n int(input()) list1 list(map(int, input().split())) dic {} for i in range(n):if not list1[i] in dic.keys():dic[list1[i]] 1else:dic[list1[i]] dic[list1[i]] 1print(dic[list1[i]], end" ")