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

JWT知识点

什么是JWT

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

基于token的认证和传统的session认证的区别

传统的session认证
我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。
但是这种基于session的认证使应用本身很难得到扩展,随着不同客户端用户的增加,独立的服务器已无法承载更多的用户,而这时候基于session认证应用的问题就会暴露出来.
基于session认证所显露的问题
Session: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。
扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。
CSRF: 因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。
基于token的鉴权机制
基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。
流程上是这样的:
• 用户使用用户名密码来请求服务器
• 服务器进行验证用户的信息
• 服务器通过验证发送给用户一个token
• 客户端存储token,并在每次请求时附送上这个token值
• 服务端验证token值,并返回数据
这个token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了*Access-Control-Allow-Origin:

JWT的组成:

JWT是由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。

在这里插入代码片

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
header
jwt的头部承载两部分信息:
• 声明类型,这里是jwt
• 声明加密的算法 通常直接使用 HMAC SHA256
playload
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分
• 标准中注册的声明
• 公共的声明
• 私有的声明
signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
• header (base64后的)
• payload (base64后的)
• secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

在这里插入代码片

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
优点
• 因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
• 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
• 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
• 它不需要在服务端保存会话信息, 所以它易于应用的扩展
安全相关
• 不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。
• 保护好secret私钥,该私钥非常重要。
• 如果可以,请使用https协议

如何应用

一:导入依赖

 <!--实现方式一:java-jwt --><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.11.0</version></dependency><!--实现方式二:jjwt--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency>

实现方式一:JWT的测试类

package comzuxia;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.util.Calendar;@SpringBootTest
class JwrloginApplicationTests {//HMAC256是摘要算法,跟md5类似,只是这个歌HMAC256需要制定key而已(salt盐)String key="pgg123456";/*** 测试java-jwt生成token字符串*/@Testpublic void testGenerateToken(){Calendar calendar=Calendar.getInstance();calendar.add(Calendar.SECOND,60);//设置过期时间JWTCreator.Builder builder = JWT.create()//payload的内容,由一个个的claim组成.withClaim("userId", 123).withClaim("userName", "Java").withClaim("url", "http://www.roadjava.com").withExpiresAt(calendar.getTime());String token = builder.sign(Algorithm.HMAC256(key));//设置签名,参数为加密算法,算法的参数:key(salt盐)System.out.println(token);}

实现方式二:JJWT的测试类

package comzuxia;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;@SpringBootTest
class JJWTTest {//HMAC256是摘要算法,跟md5类似,只是这个歌HMAC256需要制定key而已(salt盐)String key="pgg123456";/*** 测试java-jwt生成token字符串*/@Testpublic void testGenerateToken(){//过期时间Calendar calendar=Calendar.getInstance();calendar.add(Calendar.SECOND,60*60);//设置过期时间//创建payload的私有声明,(根据业务需要添加)Map<String,Object> claims=new HashMap<>();claims.put("userId", 123);claims.put("userName", "Java");claims.put("url", "http://www.roadjava.com");JwtBuilder builder = Jwts.builder()//payload的内容,由一个个的claim组成.setClaims(claims).setExpiration(calendar.getTime())//设置签名使用的签名算法和签名使用的秘钥.signWith(SignatureAlgorithm.HS256,key);String compact = builder.compact();System.out.println(compact);}/*** 校验*/@Testpublic void testVerigy(){String token="eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6IkphdmEiLCJleHAiOjE2MzcyMjk1NzIsInVzZXJJZCI6MTIzLCJ1cmwiOiJodHRwOi8vd3d3LnJvYWRqYXZhLmNvbSJ9.5i1cXxMQdCBWtNDtwH1M69XbHX3EWpOqQUnmTGwExZo";Claims claims=Jwts.parser()//得到DefaultJwtParser.setSigningKey(key)  //设置签名的秘钥.parseClaimsJws(token).getBody();//设置需要解析的jwtInteger userid= claims.get("userid",Integer.class);String userName=claims.get("userName",String.class);String url=claims.get("url",String.class);System.out.println("userid:"+userid);System.out.println("userName:"+userName);System.out.println("url:"+url);}
}

二:编写工具类
JWT的工具类

package comzuxia.util;import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import comzuxia.bean.UserInfo;
import java.util.Calendar;/*** jwt实现的方式*/
public class JwtUtil {//设置盐private static final String KEY="1234fdsaf";//方法一:用jwt生成token的方法public static String generateToken(UserInfo userInfo) {Calendar calendar=Calendar.getInstance();calendar.add(Calendar.SECOND,60);//设置过期时间JWTCreator.Builder builder = JWT.create()//payload的内容,由一个个的claim组成.withClaim("userInfo", JSON.toJSONString(userInfo)).withExpiresAt(calendar.getTime());String token = builder.sign(Algorithm.HMAC256(KEY));//设置签名,参数为加密算法,算法的参数:key(salt盐)return token;}//检验public static DecodedJWT verify(String tokenToBeVerify){DecodedJWT verify=null;try {verify = JWT.require(Algorithm.HMAC256(KEY)).build().verify(tokenToBeVerify);}catch ( Exception e){e.printStackTrace();System.out.println("出异常了");}return verify;}//解析为实体对象public static UserInfo parse(DecodedJWT decodedJWT){Claim claim = decodedJWT.getClaim("userInfo");if(claim!=null){String userString=claim.asString();UserInfo userInfo=JSON.parseObject(userString,UserInfo.class);return userInfo;}return null;}
}

JJWT的工具类

在这里插入代码片

实体类

package comzuxia.bean;public class UserInfo {private Integer id;private String name;private String address;public UserInfo() {}public UserInfo(Integer id, String name, String address) {this.id = id;this.name = name;this.address = address;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}
}

相关文章:

  • 8.Gin 自定义控制器
  • Flutter笔记:使用相机
  • Linux应用开发基础知识——网络通信编程(九)
  • Debian 12 / Ubuntu 22.04 安装 Docker 以及 Docker Compose 教程
  • 容器 - 八大架构的演进
  • 深度学习中的图像处理(基本介绍+示例代码)
  • Python---函数的应用案例(多个)
  • Laravel/Lumen 任务调度简易入门说明
  • Windows系统搭建VisualSVN服务并结合内网穿透实现公网访问
  • 【C++进阶之路】第九篇:特殊类设计
  • STM32 寄存器配置笔记——系统时钟配置 HSE as PLL
  • web:[GXYCTF2019]禁止套娃
  • gwas数据获取如何获取完整的GWAS summary数据(1)------GWAS catalog数据库
  • 【JavaEE初阶】 JavaScript基础语法——贰
  • R语言——taxize(第三部分)
  • [译]如何构建服务器端web组件,为何要构建?
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 3.7、@ResponseBody 和 @RestController
  • android 一些 utils
  • extjs4学习之配置
  • HashMap ConcurrentHashMap
  • Java知识点总结(JavaIO-打印流)
  • js
  • laravel5.5 视图共享数据
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • leetcode46 Permutation 排列组合
  • MQ框架的比较
  • mysql innodb 索引使用指南
  • mysql常用命令汇总
  • MySQL的数据类型
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • 闭包--闭包之tab栏切换(四)
  • 通信类
  • 消息队列系列二(IOT中消息队列的应用)
  • 小李飞刀:SQL题目刷起来!
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 交换综合实验一
  • 京东物流联手山西图灵打造智能供应链,让阅读更有趣 ...
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​Linux·i2c驱动架构​
  • #define 用法
  • #git 撤消对文件的更改
  • #NOIP 2014#Day.2 T3 解方程
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (8)STL算法之替换
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (第61天)多租户架构(CDB/PDB)
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • (转)jQuery 基础
  • .Net CoreRabbitMQ消息存储可靠机制
  • .Net MVC4 上传大文件,并保存表单