我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JWT全面解读和详细使用步骤

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JWT全面解读和详细使用步骤

前言

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

JWT官网

由于HTTP协议是无状态的,这意味着如果我们想判定一个接口是否被认证后访问,就需要借助cookie或者session会话机制进行判定,但是由于现在的系统架构大部分都不止一台服务器,此时又要借助数据库或者全局缓存 做存储,这种方案显然受限太多。

那么我们可不可以让认证令牌的发布者自己去识别这个令牌是不是我曾经发布的令牌呢(JWT核心思想),这是JWT最大的优点也是最大的缺点,优点是简单快捷、不需要依赖任何第三方操作就能实现身份认证,缺点就是对于任何拥有用户发布令牌的请求都会认证通过。

JWT的数据结构

正常的JWT数据结构应该如下

它是一个很长的字符串,中间用点(.)分隔成三个部分

JWT的三个部分依次: Header - 头部 、Payload - 负载 、Signature(签名)

即:Header.Payload.Signature

Header

Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。


{
"alg": "HS256",
"typ": "JWT"
}

alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT

Payload

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。

  1. iss (issuer):签发人
  2. exp (expiration time):过期时间
  3. sub (subject):主题
  4. aud (audience):受众
  5. nbf (Not Before):生效时间
  6. iat (Issued At):签发时间
  7. jti (JWT ID):编号

除了官方字段,你还可以在这个部分定义私有字段


{
"sub": "1234567890",
"name": "John Doe",
"age": "19"
}

注意:JWT默认是明文展示,任何人都可以读取到,所以此处不要放私密信息

这个 JSON 对象也要使用 Base64URL 算法转成字符串。

Signature

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。


  HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

Base64URL

前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法

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";
	
	
	
	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;
	    }
	}
	
	
	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;
	    }
	}
	
	
	
	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;
	    }
	}
	
	
	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全面解读和详细使用步骤的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JWT全面解读和详细使用步骤

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

vue3中使用vuex和vue-router的详细步骤

这篇文章主要介绍了vue3中使用vuex和vue-router的步骤,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2022-12-08

Discuz怎么使用?详细操作步骤解析

Discuz怎么使用?详细操作步骤解析,需要具体代码示例Discuz是一款知名的论坛程序,广泛应用于各种网站社区。本文将详细介绍Discuz的使用方法,包括安装、配置、创建版块以及常见操作等内容。希望能帮助读者更好地了解和使用Discuz
Discuz怎么使用?详细操作步骤解析
2024-03-02

C++封装静态链接库和使用的详细步骤

这篇文章主要介绍了C++封装静态链接库和使用,本文描述了怎么去把一个C++程序封装成一个静态库并且如何去使用这些静态库,需要的朋友可以参考下
2022-11-13

dedecms RSS全站静态输出和RSS订阅的步骤详细解答

首先,你新建一个rss.php文件,把下面的代码拷贝到其中: 复制代码代码如下:
2022-06-12

HTTP525状态码解析:详细解读其意义和使用场景

HTTP状态码是用来表示客户端请求与服务器响应之间的状态的一种规范化的方式。其中,HTTP 525状态码是指SSL连接失败。本文将详细解析HTTP 525状态码的意义和使用场景。首先,HTTP 525状态码表示SSL连接失败。SSL(Se
HTTP525状态码解析:详细解读其意义和使用场景
2024-02-22

使用VMware 15 安装虚拟机和使用CentOS 8的步骤详解

前言: 最近在学习linux和.Net Core,学习一些跨平台的知识。首先我用的虚拟机软件是VMware-15.1.0,Linux系统是CentOS-8-x86_64-1905-dvd1。 一、安装VMwNTEqQCare 15.0 首先
2022-06-04

SpringMVC加载控制与Postmand的使用和Rest风格的引入及RestFul开发全面详解

SpringMVC是一种基于Java,实现了WebMVC设计模式,请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将Web层进行职责解耦。基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,SpringMVC也是要简化我们日常Web开发
2022-11-13

javascript当来子数据源的全部有效数据读取完毕时触发此事件使用什么函数,详细讲解

当从数据源读取完所有有效数据时,JavaScript中会触发"load"事件。该事件常用于获取所有数据后再处理、错误处理和进度监控。使用XMLHttpRequest对象的onload属性来侦听此事件,并在数据完全加载后执行处理函数。注意,该事件不适用于流式数据源,并且可能比readystatechange事件稍晚触发。
javascript当来子数据源的全部有效数据读取完毕时触发此事件使用什么函数,详细讲解
2024-04-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录