Jwt的新手入门教程
Jwt的新手入门教程
1.Jwt究竟是什么东东?
先贴官网地址:JSON Web Tokens - jwt.io

再贴官方的定义:
What is JSON Web Token?
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
Although JWTs can be encrypted to also provide secrecy between parties, we will focus on signed tokens. Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. When tokens are signed using public/private key pairs, the signature also certifies that only the party holding the private key is the one that signed it.
我的理解总结:Jwt全称是Json Web Token,顾名思义就是一种通过Json方式来传输的令牌,并且他最大的特点就是signed tokens,签发者可以使用各种的加密方式对信息进行签名,更重要的是Jwt还能验证token是否被篡改或者token是否正确。当然了,这种方式注定是不安全的。我们很容易地就可以在官网得到这一结论。
可以看到,只要我们获得token字符串,就可以获取到里面的大部分信息,除了签名的密钥。
所以Jwt简单来说,就是简单地存储部分不那么重要的信息,通过Json,对客户端进行验证的一种方式。
2.Jwt的组成
从官网的Debugger界面,我们可以得知,Jwt由三部分组成。
- 第一部分:Header,Header通常由令牌的类型和加密的算法组成,也就是
{
"alg": "HS256",
"typ": "JWT"
}
这个Header的含义就是"alg"--Algorithm(算法) 是HS256。
- 第二部分: Payload,这部分主要是记录我们所存储的简单且不重要的信息。例如:用户名,过期时间,用户id等等。
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
但是要注意的是,Payload记录的这些信息是完全公开的,所以千万不能把用户或者系统的敏感数据放到Payload中,Payload只是负责记录简单信息,并不具备加密的功能。
- 第三部分:Signature, 签名里是由三部分组成,Header的Base64编码,Payload的Base64编码,还有secret,然后通过指定的加密方式,例如HS256,进行加密后得出的字符串。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
可以说这部分是Jwt的重点,因为他承担着两个作用,第一个:验证JwtToken在传输过程中没有受到篡改 第二个:验证签发人的身份
详细说一下这两个作用。
验证JwtToken在传输过程中没有受到篡改,这个原理就比较好理解,因为Signature中有一个字符串,也就是secret,这个secret是由我们来设置的,相当于私钥,只有我们自己才知道,别人是不知道的。那么在后续验证过程中,只要我们自己生产的Token与客户端传来的Token进行比对,如果一致那就证明该Token没有受到篡改,反之则证明客户端传来的Token是非法的。
验证签发人的身份,其实第二个作用是从第一个作用中展现而来的,因为如果能证明Token在传输过程中没有受到篡改,那就更加说明服务端是这个签名的签发者,因为只有签发者才知道私钥。
其实secret我们也可以认为是盐(salt),我们知道如果单纯地在数据库中存储明文密码,或者是只经过一重MD5加密的密码,是非常的不安全,因为就算是经过MD5加密,仍然可以通过暴力穷举的方式来进行破解,可是如果在用户密码的基础上,加上我们生成的随机或固定的字符串,然后再进行加密,那么安全程度会大大提升。
如果不知道盐(salt)的童鞋,可以去bind搜索一下相关资料,其实理解起来就是用户密码+我们设置的随机或固定字符串再进行多重加密。
3.编码实现
我们来创建这几个类。

配置类:InterceptorConfig
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
@Bean
public JwtInterceptor authenticationInterceptor() {
return new JwtInterceptor();
}
}
控制类: UserController
@RestController
public class UserController {
@PostMapping("/login")
public Map<String, Object> login(@RequestBody User user) {
Map<String, Object> map = new HashMap<>();
String username = user.getUsername();
String password = user.getPassword();
// 省略 账号密码验证
// 验证成功后发送token
String token = JwtUtil.sign(username, password);
if (token != null) {
map.put("code", "200");
map.put("message", "认证成功");
map.put("token", token);
return map;
}
map.put("code", "403");
map.put("message", "认证失败");
return map;
}
@GetMapping(value = "/api/test")
public String get(){
System.out.println("执行了get请求");
return "success";
}
}
服务类:UserService
@Service
public class UserService {
public String getPassword(){
return "admin";
}
}
实体类 User
@Data
public class User {
private String username;
private String password;
}
自定义拦截器类 JwtIntercepter
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 从 http 请求头中取出 token
String token = request.getHeader("token");
// 如果请求不是映射到方法直接通过
if(!(handler instanceof HandlerMethod)){
return true;
}
if (token != null){
String username = JwtUtil.getUserNameByToken(request);
// 这边拿到的 用户名 应该去数据库查询获得密码,简略,步骤在service直接获取密码
boolean result = JwtUtil.verify(token,username,userService.getPassword());
if(result){
System.out.println("通过拦截器");
return true;
}
}
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
Jwt工具类 JwtUtil
public class JwtUtil {
// Token一天后过期
public static final long EXPIRE_TIME = 1000 * 60 * 60 * 24;
//检验Token是否正确
public static boolean verify(String token, String username, String secret) {
try {
// 设置加密算法
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("username", username)
.build();
// 效验TOKEN
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception exception) {
return false;
}
}
public static String sign(String username, String secret) {
//现在系统的时间 + 一天
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
//对密码进行加密
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带username信息
return JWT.create()
.withClaim("username", username)
.withExpiresAt(date)
.sign(algorithm);
}
public static String getUserNameByToken(HttpServletRequest request) {
String token = request.getHeader("token");
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username")
.asString();
}
}
具体代码,我上传到github上:Alickx/JwtTokenDemo: JwtDemo代码 (github.com)
这里代码的secret则是用户的密码。
我们先通过PostMan向/login接口发送我们的账号密码,得到Jwt根据我们的账号密码生成的token。
{
"code": "200",
"message": "认证成功",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzIzMTg1NjksInVzZXJuYW1lIjoiYWRtaW4ifQ.c_m3z11UOcFcS_hZN9KNlidzZ2j6y_Ugkb9awHQ3FGY"
}

这里认证成功后,服务器如果不经过我们其他的存储操作,是不会对生成的token进行持久化或其他控制的,所以一旦签发出去,这个token串就会变成无状态了。
接着,我们访问一下我们的api测试接口,因为我们在config里配置了全局拦截器,且重写了HandlerInterceptor类,除了/login路径,其他全路径都需要请求的Header(请求头)中带有token字段,且需验证token成功后才会允许访问,否则进行拦截。

4.管理JwtToken的状态
要做到管理JwtToken的状态,我们可以通过把token存储到Redis数据库中,通过设置key的过期时间,就可以做到对Jwt的过期操作,同时也能够对Token进行续签,失效等等操作。这部分先不去仔细探究,有个思路就可以了。具体的编码实现我相信也不难。
本文中所有的代码均已上传到github上,如有需要请下载。
Alickx/JwtTokenDemo: JwtDemo代码 (github.com)
Jwt的新手入门教程的更多相关文章
- 安卓自动化测试(2)Robotium环境搭建与新手入门教程
Robotium环境搭建与新手入门教程 准备工具:Robotium资料下载 知识准备: java基础知识,如基本的数据结构.语法结构.类.继承等 对Android系统较为熟悉,了解四大组件,会编写简单 ...
- Xorboot-UEFI新手入门教程
Xorboot-UEFI新手入门教程 Xorboot-UEFI是一款UEFI下轻量级的图形化多系统引导程序,pauly于2014年国庆节期间发布了预览版.搜了下论坛,关于Xorboot- ...
- gulp的使用以及Gulp新手入门教程
Gulp新手入门教程 原文 http://w3ctrain.com/2015/12/22/gulp-for-beginners/ Gulp 是一个自动化工具,前端开发者可以使用它来处理常见任务: 搭 ...
- 【LaTeX】E喵的LaTeX新手入门教程(6)中文
假期玩得有点凶 ._.前情回顾[LaTeX]E喵的LaTeX新手入门教程(1)准备篇 [LaTeX]E喵的LaTeX新手入门教程(2)基础排版 [LaTeX]E喵的LaTeX新手入门教程(3)数学公式 ...
- 【LaTeX】E喵的LaTeX新手入门教程(4)图表
这里说的不是用LaTeX画图,而是插入已经画好的图片..想看画图可以把滚动条拉到底.前情回顾[LaTeX]E喵的LaTeX新手入门教程(1)准备篇 [LaTeX]E喵的LaTeX新手入门教程(2)基础 ...
- 【LaTeX】E喵的LaTeX新手入门教程(5)参考文献、文档组织
这不是最后一篇,明天开始建模所以会从6号开始继续更新.前情回顾[LaTeX]E喵的LaTeX新手入门教程(1)准备篇 [LaTeX]E喵的LaTeX新手入门教程(2)基础排版 [LaTeX]E喵的La ...
- 【LaTeX】E喵的LaTeX新手入门教程(3)数学公式
昨天熄灯了真是坑爹.前情回顾[LaTeX]E喵的LaTeX新手入门教程(1)准备篇 [LaTeX]E喵的LaTeX新手入门教程(2)基础排版上一期测试答案1.大家一开始想到的肯定是\LaTeX{}er ...
- 【LaTeX】E喵的LaTeX新手入门教程(1)准备篇
昨天熄灯了真是坑爹.前情回顾[LaTeX]E喵的LaTeX新手入门教程(1)准备篇 [LaTeX]E喵的LaTeX新手入门教程(2)基础排版上一期测试答案1.大家一开始想到的肯定是\LaTeX{}er ...
- 【LaTeX】E喵的LaTeX新手入门教程(2)基础排版
换了块硬盘折腾了好久..联想的驱动真坑爹.前情回顾[LaTeX]E喵的LaTeX新手入门教程(1)准备篇文档框架嗯昨天我们已经编写了一个最基本的文档,其内容是这样的:\documentclass{ar ...
随机推荐
- 前端 | Nuxt.js axios baseURL,proxy 代理
平时用 Vue 写前端时,对于 axios 请求的常规操作一般是 统一定义好一个 axios 对象,使用 axios.defaults.baseURL 设置 baseURL 也不是不能直接把服务器地址 ...
- VIM的跨行查找和匹配数量
跨行用\n表示,例如 用4\n56可以匹配到: 4 56 中,查询一段文本中pattern出现的次数,类似于UltraEdit中的"Count All"功能,用:%s/patter ...
- WPF 图表控件之曲线绘制与移动
目的:绘制简单轻量级的曲线视图 二.实现效果: 1,绘制标准基准线 2,可拖动 三.用到控件 1,Canvas 2,Ellipse XAML代码: <Canvas Background=&quo ...
- eclipse选中参数高亮显示设置
window - preference - java - Editor - Mark Occurrences
- MySQL-09-SQL执行计划
SQL执行计划获取及分析 介绍 (1)获取到的是优化器选择完成的,他认为代价最小的执行计划. 作用: 语句执行前,先看执行计划信息,可以有效的防止性能较差的语句带来的性能问题. 如果业务中出现了慢语句 ...
- Linux sudo权限提升漏洞CVE-2021-3156 POC及复现过程
漏洞简介 2021年1月26日,国外研究团队披露了sudo 中存在的堆溢出漏洞(CVE-2021-3156).利用该漏洞,非特权账户可以使用默认的sudo配置主机上获取root权限,该漏洞影响1.8. ...
- 题解 w
传送门 一直觉得有点后效性什么的,也不知道怎么写 这题什么时候再康一遍,第一次见这个样子的树形DP,是个树上带不定权边的DP(??? 这里能树形DP的原因好像是在这里所有子节点的状态都能表示出来 还有 ...
- Windows安装Svn客户端
一.下载程序 官网地址,选择最新64位下载. 下载完成 二.安装过程 点击下一步 点击下一步 选择安装目录 点击安装 安装完成 三.修改中文 下载中文包 下载完成 点击下一步 安装完成 点击设置 选择 ...
- Mybatis框架及原理实例分析
摘要 本篇文章只是个人阅读mybatis源码总结的经验或者个人理解mybatis的基本轮廓,作为抛砖引玉的功能,希望对你有帮助,如果需要深入了解细节还需亲自去阅读源码. mybatis基本架构 myb ...
- WPF控件自定义样式(FasControls)
一.界面预览