JWT详解
1.前言
定义:JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案
由于HTTP协议是无状态的,这意味着如果我们想判定一个接口是否被认证后访问,就需要借助cookie或者session会话机制进行判定,但是由于现在的系统架构大部分都不止一台服务器,此时又要借助数据库或者全局缓存 做存储,这种方案显然受限太多。
那么我们可不可以让认证令牌的发布者自己去识别这个令牌是不是我曾经发布的令牌呢(JWT核心思想),这是JWT最大的优点也是最大的缺点,优点是简单快捷、不需要依赖任何第三方操作就能实现身份认证,缺点就是对于任何拥有用户发布令牌的请求都会认证通过。
2.JWT的数据结构
正常的JWT数据结构应该如下
它是一个很长的字符串,中间用点(.
)分隔成三个部分
JWT的三个部分依次: Header - 头部 、Payload - 负载 、Signature(签名)
即:Header.Payload.Signature
2.1 Header
Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。
{
"alg": "HS256",
"typ": "JWT"
}
alg
属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ
属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT
2.2 Payload
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号
除了官方字段,你还可以在这个部分定义私有字段
{
"sub": "1234567890",
"name": "John Doe",
"age": "19"
}
注意:JWT默认是明文展示,任何人都可以读取到,所以此处不要放私密信息
这个 JSON 对象也要使用 Base64URL 算法转成字符串。
2.3 Signature
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.
)分隔,就可以返回给用户。
2.4 Base64URL
前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。
JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+
、/
和=
,在 URL 里面有特殊含义,所以要被替换掉:=
被省略、+
替换成-
,/
替换成_
。这就是 Base64URL 算法
3. JWT的实现
Maven依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.5.0</version>
</dependency>
JWT签名发布和验证代码
public class TokenUtil {
//Token的过期时间
private static final long EXPIRE_TIME = 30 * 60 * 1000;
//Token的私钥
private static final String TOKEN_SECRET = "jytoken_secret";
/**
* 生成签名,30分钟过期
* @param **userInfo** 用户信息 用户姓名
* @param **other** 用户其他信息 用户id
* @return
*/
public static String sign(String userInfo, String other) {
try {
// 设置过期时间
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
//私钥和加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
// 设置头部信息
Map<String, Object> header = new HashMap<>(2);
header.put("Type", "Jwt");
header.put("alg", "HS256");
// 返回token字符串
return JWT.create()
.withHeader(header)
.withClaim("userInfo", userInfo)
.withClaim("other", other)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 生成签名,30分钟过期
* @param **userInfo** 用户信息 用户姓名
* @param **other** 用户其他信息 用户id
* @return
*/
public static String sign(String userInfo, String other,long expire) {
try {
// 设置过期时间
Date date = new Date(System.currentTimeMillis() + expire);
//私钥和加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
// 设置头部信息
Map<String, Object> header = new HashMap<>(2);
header.put("Type", "Jwt");
header.put("alg", "HS256");
// 返回token字符串
return JWT.create()
.withHeader(header)
.withClaim("userInfo", userInfo)
.withClaim("other", other)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 检验token是否正确
* @param **token**
* @return
*/
public static boolean verify(String token){
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
verifier.verify(token);//未验证通过会抛出异常
return true;
} catch (Exception e){
return false;
}
}
/**
* 从token中获取info信息
* @param **token**
* @return
*/
public static String getUserName(String token,String info){
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim(info).asString();
} catch (JWTDecodeException e){
e.printStackTrace();
}
return null;
}
}
拦截器配置无需认证的请求
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Autowired
private TokenHandler tokenHandler;
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> excludePath = new ArrayList<>();
String checkLogin = "/pushlogin/checkIsCanLogin";
String login = "/pushlogin/login";
String getVerifyCode = "/common/send";
String verfifyMethod = "/common/validationCode";
excludePath.add(checkLogin);
excludePath.add(login);
excludePath.add(getVerifyCode);
excludePath.add(verfifyMethod);
registry.addInterceptor(tokenHandler).excludePathPatterns(excludePath);
}
}
Token统一拦截器代码
@Component
@Slf4j
public class TokenHandler implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authentication");
if (token != null){
boolean result = TokenUtil.verify(token);
if(result){
log.info("通过拦截器");
return true;
}
}
log.info("认证失败");
return false;
}
}
用户登录时验证用户信息后,返回Token信息
@Override
public UserDTO selectIsExistUserInfo(String phone) {
//TODO 伪代码 验证用户信息
UserDTO info = 查询用户信息
if (info != null) {
String token = TokenUtil.sign(info.getUsername(), info.getUserId(), 6 * 60 * 60 * 1000);
info.setToken(token);
}
return info;
}
JWT详解的更多相关文章
- SpringSceurity(6)---JWT详解
SpringSceurity(6)---JWT详解 在JWT之前我们在做用户认证的时候,基本上会考虑session 和 token,所以在讲jwt之前,我们先来回顾下这个两个 一.传统的session ...
- 授权认证登录之 Cookie、Session、Token、JWT 详解
一.先了解几个基础概念 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份. 互联网中的认证: 用户名密码登录 邮箱发送登录链接 手机号接收验证码 只要你能收到邮箱/验证码,就 ...
- Json Web Token(JWT)详解
什么是Json Web Token Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的 ...
- 全栈项目|小书架|服务器开发-JWT 详解
JWT 官方简介:Introduction to JSON Web Tokens 文章基本是官网内容的翻译,英文不错的同学可点击上面的链接直接看英文文档. 什么是 JWT JWT全称是JSON Web ...
- JWT详解-(JSON Web Token教程)
JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理和用法. 一.跨域认证的问题 互联网服务离不开用户认证.一般流程是下面这样. 1.用户向服务器发送用户名和密 ...
- JWT(Json web token)认证详解
JWT(Json web token)认证详解 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该to ...
- IdentityServer4实战 - JWT Token Issuer 详解
原文:IdentityServer4实战 - JWT Token Issuer 详解 一.前言 本文为系列补坑之作,拖了许久决定先把坑填完. 下文演示所用代码采用的 IdentityServer4 版 ...
- 前后端分离,简单JWT登录详解
前后端分离,简单JWT登录详解 目录 前后端分离,简单JWT登录详解 JWT登录流程 1. 用户认证处理 2. 前端登录 3. 前端请求处理 4. 后端请求处理 5. 前端页面跳转处理 6. 退出登录 ...
- JWT基础概念详解
JWT基础概念详解 JWT介绍 之前我们文章讲过分布式session如何存储,其中就讲到过Token.JWT.首先,我们来回顾一下使用Token进行身份认证. 客户端发送登录请求到服务器 服务器在用户 ...
随机推荐
- 03-Spring profile实用精简版介绍
为什么说是实用精简版,没办法,工作太忙压力大啊,菜是原罪啊,所以接下来写的一些博客可能都是更偏实用性,精简点,方便自己回顾,快速上手使用即可,毕竟感觉不详细还有书不是吗. profile是用来干什么的 ...
- scrapy基础知识之 parse()方法的工作机制思考:
1.因为使用的yield,而不是return.parse函数将会被当做一个生成器使用.scrapy会逐一获取parse方法中生成的结果,并判断该结果是一个什么样的类型: 2.如果是request则加入 ...
- Java学习笔记之---面向对象
Java学习笔记之---面向对象 (一)封装 (1)封装的优点 良好的封装能够减少耦合. 类内部的结构可以自由修改. 可以对成员变量进行更精确的控制. 隐藏信息,实现细节. (2)实现封装的步骤 1. ...
- 【POJ - 3050】Hopscotch (dfs+回溯)
-->Hopscotch 这接写中文了 Descriptions: 奶牛们以一种独特的方式玩孩子们的跳房子游戏. 奶牛们创造了一个5x5的格子 他们熟练地跳上其中的一个格子,可以前后左右地跳(不 ...
- [Usaco2007 Open]Fliptile 翻格子游戏题解
问题 B: [Usaco2007 Open]Fliptile 翻格子游戏 时间限制: 5 Sec 内存限制: 128 MB 题目描述 Farmer John knows that an intell ...
- MyBatis从入门到精通:使用XML方式(映射文件之类的)
2.3节笔记部分: package tk.mybatis.simple; public class Temp { } /* 2.2 使用XML方式 MyBatis使用了Java的动态代理可以直接通过接 ...
- JVM的内存区域
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域, 包含程序计数器.虚拟机栈.本地方法栈.Java堆.方法区(运行时常量池).直接内存等,不同的版本会有所差异 各区 ...
- 个人永久性免费-Excel催化剂功能第57波-一键生成完全组合的笛卡尔积结果表
在数据库的多表查询中,通常会有各种连接关系,同样地在Excel环境中,也有很大的场景需要用到类似数据库的多表查询,如经典的VLOOKUP就是其中一种类似LEFT JOIN查询的查询效果.在很多时候需要 ...
- 个人永久性免费-Excel催化剂功能第35波-Excel版最全单位换算,从此不用到处百度找答案
全球化的今天,相信我们经常可以有机会接触到外国的产品,同时我们也有许多产品出口到外国,国与国之间的度量单位不一,经常需要做一些转换运算,一般网页提供这样的转换,但没有什么比在Excel上计算来得更为方 ...
- Excel催化剂开源第23波-VSTO开发辅助录入功能关键技术
Excel催化剂开源第23波-VSTO开发辅助录入功能关键技术 Excel催化剂 2019.01.12 14:10* 字数 2948 阅读 41评论 0喜欢 0 编辑文章 在Excel催化剂的几大 ...