概述

JWT,Java Web Token,通过 JSON 形式作为 Web 应用中的令牌,用于在各方之间安全地将信息作为 JSON 对象传输,在数据传输过程中还可以完成数据加密、签名等相关处理

JWT 的作用如下:

  • 授权:一旦用户登录,每个后续请求将包括 JWT,从而允许用户访问该令牌允许的路由,服务和资源
  • 信息交换:JSON Web Token 是在各方之间安全地传输信息的好方法,因为可以对 JWT 进行签名,此外,由于签名是使用标头和有效负载计算的,因此还可以验证内容是否篡改

传统的 Session 认证

1. 认证方式

http 协议本身是一种无状态协议,这就意味着如果用户向我们的应用提供了用户名和密码进行认证,那么下次请求时还需再作一次认证。因为根据 http 协议,我们并不知道是哪个用户发出的请求,所以为了让应用能识别是哪个用户发出的请求,我们只能在服务存储一份用户登录的信息,这份登录信息会在响应传递给浏览器,告诉其保存为 cookie,以便下次请求时发送回来,这样我们就能识别请求来自哪个用户了

2. 缺点

  • 每个用户经过认证后,都要在服务端做一次记录,以方便下次鉴别。通常而言,session 都是保存在内存中的,随着认证用户的增多,服务端的开销也会明显增大
  • 用户认证之后,服务端做认证记录,如果认证的记录被保存到内存中,就意味着下次用户请求还得访问该服务器,才能拿到授权的资源,在分布式应用上,相应的限制了负载均衡器的能力,也就意味着限制了应用的扩展能力
  • 基于 cookie 进行用户识别,cookie 一旦被捕获,用户就会很容易受到跨站请求伪造的攻击
  • 在前后端分离时增加了部署的复杂性

JWT 认证

1. 认证方式

  • 前端通过 Web 表单将自己的用户名和密码发送给后端的接口,这一过程一般是 http post 请求,建议的方式是通过 SSL 加密的传输(https),从而避免敏感信息被嗅探
  • 后端核对用户名和密码成功后,将用户的 id 等其他信息作为 JWT Payload(负载),将其与头部分别进行 Base64 编码,拼接后签名,形成一个 JWT Token
  • 后端将 JWT 字符串作为登录成功的返回结果返回,前端可以将返回的结果保存在本地缓存上,退出登录时前端删除保存的 JWT 即可
  • 前端在每次请求后端带回 JWT
  • 后端检查是否存在,如验证 JWT 的有效性,检查签名是否正确,检查 Token 是否过期,检查 Token 接收方是否是自己
  • 验证通过后,后端使用 JWT 中包含的用户信息进行其他逻辑操作,返回相应结果

2. 优点

  • 简洁,可以通过 URL、POST 参数或者在 HTTP Header 发送,因为数据量小,传输速度快
  • 自包含,负载中包含了所有用户需要的信息,避免多次查询数据库
  • Token 以加密形式保存在客户端,原则上任何 web 形式都支持
  • 不需要在服务端保存会话信息,特别适用于分布式微服务

JWT 结构

通常 JWT 如下所示:xxxxx.yyyyy.zzzzz

  • 标头(Header):标头一般由两部分组成:令牌的类型和所使用的签名算法,标头使用 Base64 编码

    {
    "alg":"HS256",
    "typ":"JWT"
    }
  • 有效负载(payload):令牌的第二部分是有效负载,其中包含声明。声明是有关实体(通常是用户)和其他数据的声明。同样使用 Base64 编码。不建议放入用户的敏感信息

    {
    "sub":"12345678",
    "name":"john",
    "admin":true,
    ...
    }
  • 签名(Signature):Signature 需要使用编码后的 Header 和 Payload 以及我们提供的一个密钥,然后使用 Header 中指定签名算法,进行签名。签名的作用是保证 JWT 没有被篡改过,如:HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret)

客户端收到服务端发送的 token 后,再次请求服务端需要带上 token,此时 token 包含三部分:经过 Base64 编码的 Header、经过 Base64 编码的 Payload 和加密后的签名,服务端用自己保存的 secret 与客户端发送的 Header、Payload 运算,如果结果和客户端带回来的签名不一致,则验证失败

JWT 使用

引入依赖

<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>

生成 token

Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND, 20);
Map<String, Object> map = new HashMap<>();
String token = JWT.create().withHeader(map) // header
.withClaim("userId", 21) // payload
.withClaim("username", "yeeq")
.withExpiresAt(instance.getTime()) // 指定令牌的过期时间
.sign(Algorithm.HMAC256("FAWF2#!F@")); // 签名,并指定密钥

根据令牌和签名解析数据

// 创建验证对
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("FAWF2#!F@")).build();
// 解码后的信息
DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MDAyNTQ4NzIsInVzZXJJZCI6MjEsInVzZXJuYW1lIjoieWVlcSJ9.jo_6gKThSXUcEfH1e9bu7at9lm2zmdupwiYvMUWopls");
System.out.println(verify.getClaim("userId").asInt());
System.out.println(verify.getClaim("username").asString());

常见异常信息:

  • SignatureVerificationException:签名不一致异常
  • TokenExpiredException:令牌过期异常
  • AlgorithmMismatchException:算法不匹配异常
  • InvalidClaimException:失效的 payload 异常

JWT 封装工具类

一般结合拦截器或者网关完成认证

public class JWTUtils {

    private static final String SIGN = "FAWF2#!F@";

    /**
* 生成 token
* @param map payload 的信息
* @return token
*/
public static String getToken(Map<String, String> map) {
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DATE, 7);
JWTCreator.Builder builder = JWT.create();
// 创建 payload
map.forEach((k, v) -> {
builder.withClaim(k, v);
});
String token = builder.withExpiresAt(instance.getTime()) // 指定令牌的过期时间
.sign(Algorithm.HMAC256(SIGN)); // 签名,并指定密钥
return token;
} /**
* 验证 token 的合法性
* @param token token
*/
public static void verifyJWT(String token) {
JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
} /**
* 获取 token 的信息
* @return token 的信息
*/
public static DecodedJWT getTokenInfo(String token) {
DecodedJWT verify = JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
return verify;
}
}

jwt 学习笔记的更多相关文章

  1. golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息

    golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...

  2. golang学习笔记7 使用beego swagger 实现API自动化文档

    golang学习笔记7 使用beego swagger 实现API自动化文档 API 自动化文档 - beego: 简约 & 强大并存的 Go 应用框架https://beego.me/doc ...

  3. 【原创】SpringBoot & SpringCloud 快速入门学习笔记(完整示例)

    [原创]SpringBoot & SpringCloud 快速入门学习笔记(完整示例) 1月前在系统的学习SpringBoot和SpringCloud,同时整理了快速入门示例,方便能针对每个知 ...

  4. Spring Security + JWT学习

    开胃:Oauth2认证流程分析 现在第三方登录已经很普遍了,随便哪个App都会有使用微信登录,使用手机号码登录,或者使用支付宝登录等功能... 下面我们就以使用微信登录,做一个简单的流程分析分析 开胃 ...

  5. SpringBoot学习笔记(十五:OAuth2 )

    @ 目录 一.OAuth 简介 1.什么是OAuth 2.OAuth 角色 3.OAuth 授权流程 4.OAuth授权模式 4.1.授权码 4.2.隐藏式 4.3.密码式 4.4.凭证式 二.实践 ...

  6. 图灵学院JAVA互联网架构师专题学习笔记

    图灵学院JAVA互联网架构师专题学习笔记 下载链接:链接: https://pan.baidu.com/s/1xbxDzmnQudnYtMt5Ce1ONQ 密码: fbdj如果失效联系v:itit11 ...

  7. Spring Cloud微服务学习笔记

    Spring Cloud微服务学习笔记 SOA->Dubbo 微服务架构->Spring Cloud提供了一个一站式的微服务解决方案 第一部分 微服务架构 1 互联网应用架构发展 那些迫使 ...

  8. SpringBoot + Security学习笔记

    SpringSecurity学习笔记 本以为是总结,最后写成了笔记,所以还是需要更加的努力啊. 开始的时候看了一遍官方文档,然后只看懂了加密器. 然后又学了一个尚硅谷的视频,虽然这个教程是在讲一个项目 ...

  9. Vue学习笔记-rest_framework_jwt 学习

    一  使用环境 开发系统: windows 后端IDE: PyCharm 前端IDE: VSCode 数据库: msyql,navicat 编程语言: python3.7  (Windows x86- ...

  10. Vue学习笔记-Django REST framework3后端接口API学习

    一  使用环境 开发系统: windows 后端IDE: PyCharm 前端IDE: VSCode 数据库: msyql,navicat 编程语言: python3.7  (Windows x86- ...

随机推荐

  1. 五一训练包E-5

    题目链接:https://vjudge.net/contest/436484#problem/E 题目的大致意思就是给俩数,分别是小数组的大小N和数目K,给的数组是递增的,方便后续的判断,将大数组分成 ...

  2. SOC平台,网络安全管理平台

    SOC平台,网络安全管理平台 提供集中.统一.可视化的安全信息管理,通过实时采集各种安全信息,动态进行安全信息关联分析与风险评估,实现安全事件的快速跟踪.定位和应急响应. 从监控.审计.风险和运维四个 ...

  3. 【APT】Bitter APT组织针对巴基斯坦航空综合部门攻击活动分析

    前言 蔓灵花(Bitter)是一个被广泛认为来自印度的APT组织,该组织长期针对我国及巴基斯坦的政府.军工.电力.核等部门发动网络攻击,窃取敏感数据,具有较强的政治背景.本次分享一个蔓灵花组织针对巴基 ...

  4. 【逆向】使用IDA Python脚本自动化解密字符串数据

    前言 一个肚脑虫(Donot)APT组织的下载器样本,样本中的一些关键字符串数据需要使用指定函数进行动态解密.所以正好借此机会记录下怎么使用IDA Python脚本来解密字符串数据.使用IDA Pyt ...

  5. C++与C语言中struct 与typedef struct 应用区别(摘自csdn mpp_king)

    typedef是类型定义的意思.typedef struct 是为了使用这个结构体方便.具体区别在于:若struct node {}这样来定义结构体的话.在申请node 的变量时,需要这样写,stru ...

  6. [fiddler的使用]模拟自动回复功能在模拟测试mock第三方对接系统的返回中的使用场景

    [场景描述]在许多对第三方的测试过程中,由于第三方没有测试环境或者测试环境同步开发的时候还未准备好,或者系统间联调时对方还未完成的各种情况下,我们可以通过fiddler来模拟对方的返回. [操作步骤] ...

  7. 国际化vue-i18n 向语言包中传入参数

    模板 <span>{{$t('el.table.total', { pagetotal: 123 })}}</span> js代码中 this.$t('el.table.num ...

  8. element ui动态生成表单数据与校验(后台传入数据)

    前言 最近有一个需求是通过后台返回的数据,生成表单并添加校验.在做的过程中,动态表单挺好做,关键是校验.困扰了我2天,最后通过查找资料和"运气"终于解决了.解决问题关键点:vue的 ...

  9. [C#]协变Covariance案例

    协变参考代码1: using System; using System.Collections.Generic; using System.Linq; namespace CovarianceSoOn ...

  10. unittest框架基本使用

    1.简介 unittest是python内置的单元测试框架,具备编写用例.组织用例.执行用例.输出报告等自动化框架的条件.使用unittest前需要了解该框架的五个概念: 即test case,tes ...