1.前言

定义:JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案

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详解的更多相关文章

  1. SpringSceurity(6)---JWT详解

    SpringSceurity(6)---JWT详解 在JWT之前我们在做用户认证的时候,基本上会考虑session 和 token,所以在讲jwt之前,我们先来回顾下这个两个 一.传统的session ...

  2. 授权认证登录之 Cookie、Session、Token、JWT 详解

    一.先了解几个基础概念 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份. 互联网中的认证: 用户名密码登录 邮箱发送登录链接 手机号接收验证码 只要你能收到邮箱/验证码,就 ...

  3. Json Web Token(JWT)详解

    什么是Json Web Token Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的 ...

  4. 全栈项目|小书架|服务器开发-JWT 详解

    JWT 官方简介:Introduction to JSON Web Tokens 文章基本是官网内容的翻译,英文不错的同学可点击上面的链接直接看英文文档. 什么是 JWT JWT全称是JSON Web ...

  5. JWT详解-(JSON Web Token教程)

    JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理和用法. 一.跨域认证的问题 互联网服务离不开用户认证.一般流程是下面这样. 1.用户向服务器发送用户名和密 ...

  6. JWT(Json web token)认证详解

    JWT(Json web token)认证详解 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该to ...

  7. IdentityServer4实战 - JWT Token Issuer 详解

    原文:IdentityServer4实战 - JWT Token Issuer 详解 一.前言 本文为系列补坑之作,拖了许久决定先把坑填完. 下文演示所用代码采用的 IdentityServer4 版 ...

  8. 前后端分离,简单JWT登录详解

    前后端分离,简单JWT登录详解 目录 前后端分离,简单JWT登录详解 JWT登录流程 1. 用户认证处理 2. 前端登录 3. 前端请求处理 4. 后端请求处理 5. 前端页面跳转处理 6. 退出登录 ...

  9. JWT基础概念详解

    JWT基础概念详解 JWT介绍 之前我们文章讲过分布式session如何存储,其中就讲到过Token.JWT.首先,我们来回顾一下使用Token进行身份认证. 客户端发送登录请求到服务器 服务器在用户 ...

随机推荐

  1. 微服务-springboot打包

    idea打包方式: 打包前确认项目可以正常运行 一.File->Project Structure->Artifacts->点击 + ->JAR->From module ...

  2. pod update更新error: RPC failed; curl 18 transfer closed with outstanding read data remaining

    1. pod update 的时候出现下边的错误 error: RPC failed; curl 18 transfer closed with outstanding read data remai ...

  3. ConnectionPool实现redis在python中的连接

    这篇文章主要介绍了Python与Redis的连接教程,Redis是一个高性能的基于内存的数据库,需要的朋友可以参考下   今天在写zabbix storm job监控脚本的时候用到了python的re ...

  4. ABP开发框架前后端开发系列---(15)ABP框架的服务端和客户端缓存的使用

    缓存在一个大型一点的系统里面是必然会涉及到的,合理的使用缓存能够给我们的系统带来更高的响应速度.由于数据提供服务涉及到数据库的相关操作,如果客户端的并发数量超过一定的数量,那么数据库的请求处理则以爆发 ...

  5. Python Day_1

    听说Python很6,然后我的偶像小甲鱼竟然在6年前(现在2019年)就开始制作Python的教程,而前不久(世界读书日前一个星期左右),京东有活动,小甲鱼的Python第一版本打折,顺便买了本(还凑 ...

  6. 从零开始基于go-thrift创建一个RPC服务

    Thrift 是一种被广泛使用的 rpc 框架,可以比较灵活的定义数据结构和函数输入输出参数,并且可以跨语言调用.为了保证服务接口的统一性和可维护性,我们需要在最开始就制定一系列规范并严格遵守,降低后 ...

  7. Linux指令学习

    Linux命令格式:命令名  选项  参数 Linux 刚面世时并没有图形界面,所有的操作全靠命令完成,如 磁盘操作.文件存取.目录操作.进程管理.文件权限 设定等,在职场中,大量的服务器维护工作都是 ...

  8. 学习springboot整合mybatis并编写测试类

    报名立减200元.暑假直降6888. 邀请链接:http://www.jnshu.com/login/1/20535344 邀请码:20535344 遇到的问题: 1.原因是在启动类上只有一个@Map ...

  9. Redis主从复制实现原理

    一.Redis2.8之前的版本, 首先redis复制功能分为同步操作和命令传播两个操作 同步操作作于将从服务器的数据库状态更新至主服务器当前所处的数据库状态  命令传播操作则用于在主服务器的数据库状态 ...

  10. HDU5521 Meeting(dijkstra+巧妙建图)

    HDU5521 Meeting 题意: 给你n个点,它们组成了m个团,第i个团内有si个点,且每个团内的点互相之间距离为ti,问如果同时从点1和点n出发,最短耗时多少相遇 很明显题目给出的是个无负环的 ...