JWT 从入门到精通

什么是 JWT

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案

JSON Web Token Introduction - jwt.ioLearn about JSON Web Tokens, what are they, how they work, when and why you should use them.icon-default.png?t=N7T8https://jwt.io/introduction

一、常见会话

cookie、session、token

-cookie:客户端浏览器的键值对
-session:服务的的键值对(djangosession表,内存中,文件,缓存数据库)
-token:服务的生成的加密字符串,如果存在客户端浏览器上,就叫cookie
    -三部分:头,荷载,签名
    -签发:登录成功,签发
    -认证:认证类中认证 

 jwt (Json web token)

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

二、base64编码和解码

base64并不是一种加密反射,只是编码解码方式

  • 字符串,可以转成base64编码格式:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  • eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 解码成base64
import json
import base64d = {'user_id': 1, 'username': "lqz"}d_str = json.dumps(d)print(d_str)
# # 对字符串进行bashe64 编码
res=base64.b64encode(bytes(d_str,encoding='utf-8'))
print(res)  # eyJ1c2VyX2lkIjogMSwgInVzZXJuYW1lIjogImxxeiJ9# 解码
res=base64.b64decode('TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ=')
print(res)

ps:记住: base64 编码,长度一定是4的倍数。如果不够,用 = 补齐

base64的用途

  • 互联网中,前后端数据交互,使用base64编码
  • jwt 字符串使用base64编码
  • 互联网中一些图片,使用base64编码
s = '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'
res = base64.b64decode(s)
with open('code.png', 'wb') as f:f.write(res)

三、 JWT认证

在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token(本质就是token)认证机制

使用jwt认证和使用session认证的区别

加密原理

在对称加密的时代,加密和解密用的是同一个密钥,这个密钥既用于加密,又用于解密。这样做有一个明显的缺点,如果两个人之间传输文件,两个人都要知道密钥,如果是三个人呢,五个人呢?于是就产生了非对称加密,用一个密钥进行加密(公钥),用另一个密钥进行解密(私钥)

1.公钥私钥原理

张三有两把钥匙,一把是公钥,另一把是私钥。

张三把公钥送给他的朋友们李四、王五、赵六每人一把。

李四要给张三写一封保密的信。她写完后用张三的公钥加密,就可以达到保密的效果。

张三收信后,用私钥解密,就看到了信件内容。这里要强调的是,只要张三的私钥不泄露,这封信就是安全的,即使落在别人手里,也无法解密。

张三给李四回信,决定采用“数字签名”。他写完后先用Hash函数,生成信件的摘要(digest)。然后利用私钥将摘要进行加密,张三将这个签名,附在信件下面,一起发给李四。

李四收信后,取下数字签名,用张三的公钥解密,得到信件的摘要。由此证明,这封信确实是张三发出的。李四再对信件本身使用Hash函数,将得到的结果,与上一步得到的摘要进行对比。如果两者一致,就证明这封信未被修改过。

四、JWT生产公钥与私钥

找到JDK环境的keytool(证书管理工具)

生成私钥

keytool -genkeypair -alias test110 -keyalg RSA -keypass miyaomima -keystore xc.keystore -storepass miyaokumima

建值解释说明测试用例
-alias证书的别名test110
-keyalg

使用的hash算法

RSA
-keypass密钥的访问密码miyaomima
-keystore生成的文件的名字xc.keystore
xc.keystore保存了生成的证书
-storepass密钥库的访问密码miyaokumima

Windows系统需以管理员身份运行

 

查看证书文件是否生成成功

查看密钥

keytool -list -keystore xc.keystore

删除别名

 keytool -delete -alias test110 -keystore xc.keystore 

生成公钥

配置openssl

Win32/Win64 OpenSSL Installer for Windows - Shining Light Productionsicon-default.png?t=N7T8http://slproweb.com/products/Win32OpenSSL.html找一个合适自己计算机版本的进行配置

点击下载

这里小编使用默认路径进行安装

配置path环境变量

本教程配置在C:\Program Files\OpenSSL-Win64\bin

cmd进入xc.keystore文件所在目录执行命令 | 右键终端打开

keytool -list -rfc --keystore xc.keystore | openssl x509 -inform pem -pubkey

 

将上边的公钥拷贝到文本public.key文件中,合并为一行,可以将它放到需要实现授权认证的工程中

Attention

证书文件不要放在有中文路径下

所有文字都要在同一行

五、项目实战

引入JWT的依赖

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.10.5</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.10.5</version><scope>runtime</scope>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.10.5</version><scope>runtime</scope>
</dependency>

引入其他依赖

<dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId><version>2.9.4</version>
</dependency>
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.16</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.54</version>
</dependency>

创建User对象

public class UserInfo {private Long id;//用户IDprivate String username;//用户名称private String role;//用户角色public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getRole() {return role;}public void setRole(String role) {this.role = role;}
}

创建JWT工具类

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.UUID;public class JwtUtils {private static final String JWT_PAYLOAD_USER_KEY = "user";/*** 私钥加密token** @param info   载荷中的数据* @param privateKey 私钥* @param expire     过期时间,单位分钟* @return JWT*/public static String generateTokenExpireInMinutes(Object info, PrivateKey privateKey, int expire) {return Jwts.builder()//claim: 往Jwt的载荷存入数据.claim(JWT_PAYLOAD_USER_KEY, ObjectUtil.toString(info))//往Jwt的载荷存入数据,设置固定id的key.setId(createJTI())//往Jwt的载荷存入数据,设置固定exp的key.setExpiration(DateTime.now().plusMinutes(expire).toDate())//设置token的签名.signWith(privateKey, SignatureAlgorithm.RS256).compact();}/*** 私钥加密token** @param info   载荷中的数据* @param privateKey 私钥* @param expire     过期时间,单位秒* @return JWT*/public static String generateTokenExpireInSeconds(Object info, PrivateKey privateKey, int expire) {return Jwts.builder().claim(JWT_PAYLOAD_USER_KEY, ObjectUtil.toString(info)).setId(createJTI()).setExpiration(DateTime.now().plusSeconds(expire).toDate()).signWith(privateKey, SignatureAlgorithm.RS256).compact();}/*** 公钥解析token** @param token     用户请求中的token* @param publicKey 公钥* @return Jws<Claims>*/private static Jws<Claims> parserToken(String token, PublicKey publicKey) {return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);}private static String createJTI() {return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));}/*** 获取token中的用户信息** @param token     用户请求中的令牌* @param publicKey 公钥* @return 用户信息*/public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey, Class<T> userType) {Jws<Claims> claimsJws = parserToken(token, publicKey);Claims body = claimsJws.getBody();Payload<T> claims = new Payload<>();claims.setId(body.getId());claims.setInfo(JSONUtil.toBean(body.get(JWT_PAYLOAD_USER_KEY).toString(), userType));claims.setExpiration(body.getExpiration());return claims;}/*** 获取token中的载荷信息** @param token     用户请求中的令牌* @param publicKey 公钥* @return 用户信息*/public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey) {Jws<Claims> claimsJws = parserToken(token, publicKey);Claims body = claimsJws.getBody();Payload<T> claims = new Payload<>();claims.setId(body.getId());claims.setExpiration(body.getExpiration());return claims;}
}

 创建RSA工具类

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;public class RsaUtils {private static final int DEFAULT_KEY_SIZE = 2048;/*** 从文件中读取公钥** @param filename 公钥保存路径,相对于classpath* @return 公钥对象* @throws Exception*/public static PublicKey getPublicKey(String filename) throws Exception {byte[] bytes = readFile(filename);return getPublicKey(bytes);}/*** 从文件中读取密钥** @param filename 私钥保存路径,相对于classpath* @return 私钥对象* @throws Exception*/public static PrivateKey getPrivateKey(String filename) throws Exception {byte[] bytes = readFile(filename);return getPrivateKey(bytes);}/*** 获取公钥** @param bytes 公钥的字节形式* @return* @throws Exception*/private static PublicKey getPublicKey(byte[] bytes) throws Exception {bytes = Base64.getDecoder().decode(bytes);X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);KeyFactory factory = KeyFactory.getInstance("RSA");return factory.generatePublic(spec);}/*** 获取密钥** @param bytes 私钥的字节形式* @return* @throws Exception*/private static PrivateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {bytes = Base64.getDecoder().decode(bytes);PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);KeyFactory factory = KeyFactory.getInstance("RSA");return factory.generatePrivate(spec);}/*** 根据密文,生存rsa公钥和私钥,并写入指定文件** @param publicKeyFilename  公钥文件路径* @param privateKeyFilename 私钥文件路径* @param secret             生成密钥的密文*/public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret, int keySize) throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");SecureRandom secureRandom = new SecureRandom(secret.getBytes());keyPairGenerator.initialize(Math.max(keySize, DEFAULT_KEY_SIZE), secureRandom);KeyPair keyPair = keyPairGenerator.genKeyPair();// 获取公钥并写出byte[] publicKeyBytes = keyPair.getPublic().getEncoded();publicKeyBytes = Base64.getEncoder().encode(publicKeyBytes);writeFile(publicKeyFilename, publicKeyBytes);// 获取私钥并写出byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();privateKeyBytes = Base64.getEncoder().encode(privateKeyBytes);writeFile(privateKeyFilename, privateKeyBytes);}private static byte[] readFile(String fileName) throws Exception {return Files.readAllBytes(new File(fileName).toPath());}private static void writeFile(String destPath, byte[] bytes) throws IOException {File dest = new File(destPath);if (!dest.exists()) {dest.createNewFile();}Files.write(dest.toPath(), bytes);}
}

创建PayLoad工具类

import java.util.Date;public class Payload<T>{private String id;private T info;private Date expiration;public String getId() {return id;}public void setId(String id) {this.id = id;}public T getInfo() {return info;}public void setInfo(T info) {this.info = info;}public Date getExpiration() {return expiration;}public void setExpiration(Date expiration) {this.expiration = expiration;}
}

创建测试类

import com.alibaba.fastjson.JSONObject;public class Test {private static final  String localPath = "\\main\\java\\com\\coldwind\\xutils\\jwt\\";public static void generateKey() {String proPath = System.getProperty("user.dir") + "\\src";proPath = proPath.replaceAll("\\\\", "\\\\\\\\");String keyPath = proPath+ localPath;String priKey = keyPath + "private.key";String pubKey = keyPath + "public.key";String secret = "123456";try {RsaUtils.generateKey(pubKey, priKey, secret, 2048);} catch (Exception e) {e.printStackTrace();}}public static void test() throws Exception {String proPath = System.getProperty("user.dir") + "\\src";proPath = proPath.replaceAll("\\\\", "\\\\\\\\");String keyPath = proPath+localPath;UserInfo userInfo = new UserInfo();userInfo.setUsername("admin");userInfo.setId(1L);String token = JwtUtils.generateTokenExpireInMinutes(JSONObject.toJSONString(userInfo), RsaUtils.getPrivateKey(keyPath+"private.key"), 10);System.out.println(token);Payload<UserInfo> userInfoPayload = JwtUtils.getInfoFromToken(token, RsaUtils.getPublicKey(keyPath+"public.key"),UserInfo.class);System.out.println(JSONObject.toJSONString(userInfoPayload));}public static void main(String[] args) throws Exception {test();}}

第一步:先在执行目录下生成公钥、私钥 

第二步:模拟私钥加密

第三部:模拟公钥解密

执行效果

eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoie1wiaWRcIjoxLFwidXNlcm5hbWVcIjpcImFkbWluXCJ9IiwianRpIjoiTXprMVpEQmtOR010TWpZMFpTMDBPREl3TFRsaFpEZ3ROamRqTkdNelkyUTVNVEE1IiwiZXhwIjoxNzE3ODk3NTU2fQ.TrsJToMTUpkP6DbtyCL16-2d1WTTxPmOhb4BQyAFB6_nUg94xKu6q-lSfZNi3e7BmGxNrJYYNUyJZxaMO20ZQ88OJdeYbNfZ8ixxv2zw8QrmIFTGzHLqximXvl6kMZWEd_ArKRi2ba5NDQlTAvqJfQSv5hjiY-Rug_RX_Pd4ak81kVWOYOhJUMvsfoVlp6typoiFSWdjp024mkux4GtQfexZy0_CbLTX5KI4bVioSgxREPAhH68bmx-LcQQ9GEtcCidEZu0FsA6ubqnE0IWw5g6TJhOnuNdZOT2QWsv9WPaxhOJllV1mAqeXwnJufSZa-VUYgVjQhNnAWXbcNBSUqA
{"expiration":1717897556000,"id":"Mzk1ZDBkNGMtMjY0ZS00ODIwLTlhZDgtNjdjNGMzY2Q5MTA5","info":{"id":1,"username":"admin"}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/345500.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hadoop疑难问题解决_NoClassDefFoundError: org/apache/hadoop/fs/adl/AdlFileSystem

1、问题描述 impala执行查询&#xff1a;select * from stmta_raw limit 10; 报错信息如下&#xff1a; Query: select * from sfmta_raw limit 10 Query submitted at: 2018-04-11 14:46:29 (Coordinator: http://mrj001:25000) ERROR: AnalysisException: Failed to load …

在 SEO 中,一个好的网页必须具备哪些 HTML 标签和属性?

搜索引擎优化 &#xff08;SEO&#xff09; 是涉及提高网站在搜索引擎上的可见性的过程。这是通过提高网站在搜索引擎结果页面&#xff08;例如Google&#xff09;上的排名来实现的。网站在这些页面上的显示位置越高&#xff0c;就越有可能获得更大的流量。 搜索引擎优化涉及了…

2024国内热门大语言模型在科研方面的应用

本博客总结了几款热门的国产大语言模型&#xff0c;帮助大家利用这些大语言模型更好的进行科研。 模型介绍 1.文心一言 链接:https://yiyan.baidu.com/ 开发方&#xff1a;百度 特点&#xff1a;专注于中文语言理解与生成&#xff0c;适合中文文本的语义理解任务。 百度推出…

UnityXR Interaction Toolkit 如何使用XRHand手部识别

前言 Unity的XR Interaction Toolkit是一个强大的框架,允许开发者快速构建沉浸式的VR和AR体验。随着虚拟现实技术的发展,手部追踪成为了提升用户交互体验的关键技术之一。 本文将介绍如何在Unity中使用XR Interaction Toolkit实现手部识别功能。 准备工作 在开始之前,请…

数字科技如何助力博物馆设计,强化文物故事表现力?

国际博物馆日是每年为了推广博物馆和文化遗产&#xff0c;而设立的一个特殊的日子&#xff0c;让我们可以深入探讨博物馆如何更好地呈现和保护我们的文化遗产&#xff0c;随着近年来的数字科技发展&#xff0c;其在博物馆领域的应用越来越广泛&#xff0c;它为博物馆提供了新的…

使用vite从0开始搭建vue项目

使用Vite从0开始创建vue项目 第一步&#xff1a;创建项目目录 mkdir vue-demo -创建目录 cd vue-demo --进入项目 npm init -y --生成package.json文件 第二步&#xff1a;安装vite、typescript--ts、vue、vitejs/plugin-vue--对单文件组件、热重载、生产优化的支持 pnpm…

【Spring Boot】异常处理

异常处理 1.认识异常处理1.1 异常处理的必要性1.2 异常的分类1.3 如何处理异常1.3.1 捕获异常1.3.2 抛出异常1.3.4 自定义异常 1.4 Spring Boot 默认的异常处理 2.使用控制器通知3.自定义错误处理控制器3.1 自定义一个错误的处理控制器3.2 自定义业务异常类3.2.1 自定义异常类3…

STM32F103单片机工程移植到航顺单片机HK32F103注意事项

一、简介 作为国内MCU厂商中前三阵营之一的航顺芯片&#xff0c;建立了世界首创超低功耗7nA物联网、万物互联核心处理器浩瀚天际10X系列平台&#xff0c;接受代理商/设计企业/方案商定制低于自主研发十倍以上成本&#xff0c;接近零风险自主品牌产品&#xff0c;芯片设计完成只…

《python程序语言设计》2018版第5章第48题以0,0为圆心 绘制10个左右的同心圆

在0&#xff0c;0点处绘制10个圆。 其实这个题先要记住python不会0&#xff0c;0为原点进行绘画。 它是按半径来画&#xff0c;所以我们要先把turtle这个小画笔送到它应该去的起点。&#xff08;我经常有这样的错觉&#xff0c;每次都是这样想办法把自己拉回来&#xff09; 我…

(学习笔记)数据基建-数据安全

&#xff08;学习笔记&#xff09;数据基建-数据安全 数据安全数据安全实施难点数据安全保障流程数据安全措施实施阶段数据安全如何量化产出数据安全思考 数据安全 数据安全问题是最近比较热的话题&#xff0c;数据泄漏引发的用户信任危机事件也比比皆是&#xff0c;以及跨部门…

AWS EMR Serverless

AWS概述 EMR Serverless 简介 在AWS概述一文中简单介绍过AWS EMR, 它是AWS提供的云端大数据平台。借助EMR可以设置集群以便在几分钟内使用大数据框架处理和分析数据。创建集群可参考官方文档&#xff1a;Amazon EMR 入门。但集群创建之后需要一直运行&#xff0c;用户需要管理…

42. 接雨水

题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3,2,1…

Linux——PXE_FTP_EL8

PXE Kickstart &#xff08; el8 &#xff09; 使用两个网口一个用net接口用于下载服务和软件包&#xff0c;另一个为仅主机用于与其他的空主机相连 PXE(preboot execute environment) 预启动执行环境。支持工作站通过网络从远端服务器下载映像&#xff0c;并由此支持通过网络启…

水库大坝安全监测系统打通监控数据“最后一公里”

一、概述 我国有水库8万座左右&#xff0c;其中土石坝多数&#xff0c;病险水库占水库也很多。众所周知&#xff0c;水库在防洪、兴利上具有重要的调节作用&#xff0c;如何保证水库安全&#xff0c;及合理有效的利用水资源&#xff0c;是水利建设者需要探讨的主要内容。科学技…

中国宠业新锐品牌展,2024苏州国际宠物展6月28日开展!

中国宠业新锐品牌展&#xff0c;2024苏州国际宠物展6月28日开展&#xff01; ​ 第2届华东国际宠物用品展览会(苏州)暨中国宠业新锐品牌展&#xff0c;将于6月28日-30日在苏州国际博览中心盛大举办&#xff0c;锁定年中市场黄金档期&#xff0c;同期以“NB展&#xff0c;更新鲜…

未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序。.net 读取excel的时候报错(实测有效)

1. 下载AccessDatabaseEngine.exe 下载链接 添加链接描述 2. office excel是64为的需要安装【AccessDatabaseEngine.exe】、32位的【AccessDatabaseEngine_X64.exe】 3. 我的是64为&#xff0c;跳过32位安装检测 1. 找到下载的安装包 2.输入安装包文件全称并在后面加上/pas…

【Android】使用EventBus进行线程间通讯

EventBus 简介 EventBus&#xff1a;github EventBus是Android和Java的发布/订阅事件总线。 简化组件之间的通信 解耦事件发送者和接收者 在 Activities, Fragments, background threads中表现良好 避免复杂且容易出错的依赖关系和生命周期问题 Publisher使用post发出…

晶振十大品牌

晶振是电路的心脏&#xff0c;特别对抖动、稳定度有要求&#xff0c;当然除了稳定度&#xff0c;抖动&#xff0c;还对环境温度有要求&#xff0c;优秀的厂商如下&#xff1a; 链接&#xff1a; 晶振十大品牌-晶振品牌-振荡器品牌-Maigoo品牌榜

【端午安康,给大家讲个“网络”故事,深刻一下!】

牛马我&#x1f434;上周又挨锤了&#xff0c; 网络是不稳定的&#xff0c;博学多知的你可能知道&#xff0c;可能不知道。但假如没亲身经历过&#xff0c;知不知道都不深刻&#xff0c;牛马踩了个网络的坑&#xff0c;深刻了&#xff0c;这里分享下&#xff0c; 一个真相 无…

neo4j入门并使用案例说明

1、neo4j是什么 Neo4j是一个高性能的NoSQL图形数据库&#xff0c;它将结构化数据存储在网络&#xff08;在数学角度称为图&#xff09;上&#xff0c;而不是传统的表中。Neo4j是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java持久化引擎。它因其高性能、轻量级、易嵌入和…