03-JWT令牌和普通令牌的区别,JWT令牌的格式和生成

JWT令牌

普通令牌问题

普通令牌的问题: 以OAuth2的密码模式为例进行说明,客户端每次访问资源时, 资源服务都需要远程请求认证服务去校验令牌的合法性导致执行性能低

在这里插入图片描述

如果能够让资源服务自己校验令牌的合法性,这样就可以省去远程请求认证服务的成本并提高性能

在这里插入图片描述

常见两种认证方式

有状态认证: 基于Session的方式,用户登录成功后需要将用户的身份信息存储在服务端的Session中,这样会加大服务端的存储压力并且不适合在分布式系统中应用

在这里插入图片描述

无状态认证: 基于令牌的方式,将用户身份信息存储在令牌中,可以在分布式系统中实现认证

在这里插入图片描述

JWT令牌的格式

如果令牌采用JWT格式就可以不依赖认证服务,资源服务自己就可以自行校验令牌

  • 客户端携带用户的账号和密码授权码访问认证服务,认证通过后客户端会得到一个JWT令牌,该令牌中包括了用户相关的信息
  • 客户端只需要携带JWT令牌访问资源服务,资源服务再根据事先约定的算法自行完成令牌校验,这样就无需每次都请求认证服务进行校验

Json Web Token(JWT)是一种使用Json格式传递数据的网络令牌技术,它是一个开放的行业标准(RFC 7519)

  • JWT定义了一种简介的、自包含的协议格式, 用于在通信双方传递Json对象,传递的对象经过数字签名可以被验证和信任
  • 它可以应用HMAC算法或使用RSA的公钥/私钥来签名,防止内容篡改

JWT令牌的优缺点

  • 基于JSON便于解析, 同时可以在令牌中自定义丰富的内容易扩展
  • 通过非对称加密算法及数字签名技术,可以防止JWT被篡改安全性高
  • 缺点也就是JWT令牌较长占存储空间比较大

JWT令牌由头部,负载,签名三部分组成,每部分中间使用点.分隔

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJ6aGFuZ3NhbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2NjQyNTQ2NzIsImF1dGhvcml0aWVzIjpbInAxIl0sImp0aSI6Ijg4OTEyYjJkLTVkMDUtNGMxNC1iYmMzLWZkZTk5NzdmZWJjNiIsImNsaWVudF9pZCI6ImMxIn0.wkDBL7roLrvdBG2oGnXeoXq-zZRgE9IVV2nxd-ez_oA	

Header: 头部是个Json对象,包括令牌的类型(如JWT)及使用的签名算法(如HMAC、MD5、HS526、SHA256或RSA)

{
    "alg": "HS256",
    "typ": "JWT"
}
// 将上面的内容使用Base64Url编码得到的字符串就是JWT令牌的第一部分

Payload: 负载也是一个Json对象,它是存放有效信息的地方如用户信息,但是不建议存放敏感信息因为此部分可以解码还原得到原始内容

  • 存放JWT提供的现成字段: iss(签发者)、exp(过期时间戳)、sub(面向的用户)
  • 自定义字段: 如用户名,账号等
{
    "sub": "1234567890",
    "name": "456",
    "admin": true
}
// 将上面的内容使用Base64Url编码得到的字符串就是JWT令牌的第二部分

Sugbature: 使用Base64Url编码将前两部分进行编码,然后使用点.连接组成字符串,最后使用Header中声明的签名算法对Header和Payload中的内容进行签名

  • 我们每次访问资源时访问资源都会携带JWT令牌,所以需要使用签名算法对JWT中包含的信息进行加密,防止JWT令牌中的内容被别人解析出来后篡改
  • 签名是不可逆的,如果第三方更改了JWT令牌中的内容那么服务器验证时就会失败即需要重新获取令牌,要想保证签名正确,必须保证内容、密钥与签名前一致
HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret)// secret是密钥 	

密钥: 在使用签名算法对Header和Payload中的内容进行进行签名时需要使用密钥(这个密钥不对外公开)

  • 对称加密(效率高): 认证服务和资源服务使用相同的密钥,如果一旦密钥泄露别人就可以解析JWT令牌中的内容,然后使用同样的密钥和签名算法伪造JWT令牌
  • 非对称加密(效率低但更安全): 认证服务自己保留私钥,将公钥下发给受信任的客户端如资源服务,公钥和私钥是配对的,成对的公钥和私钥才可以正常加密、解密

在这里插入图片描述

测试认证服务生成JWT令牌

第一步: 在xuecheng-plus-auth认证服务工程的config/TokenConfig中配置令牌的生成和存储策略

@Configuration
public class TokenConfig {
    // 认证服务生成JWT令牌时的密钥
    private String SIGNING_KEY = "mq123";
    @Autowired
    TokenStore tokenStore;
    @Autowired
    private JwtAccessTokenConverter accessTokenConverter;
    @Bean
    public TokenStore tokenStore() {
        // 采用Jwt的方式存储令牌
        return new JwtTokenStore(accessTokenConverter());
    }
    // Jwt令牌转换器
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(SIGNING_KEY);
        return converter;
    }
    //令牌管理服务
    @Bean(name = "authorizationServerTokenServicesCustom")
    public AuthorizationServerTokenServices tokenService() {
        DefaultTokenServices service = new DefaultTokenServices();
        service.setSupportRefreshToken(true);//支持刷新令牌
        service.setTokenStore(tokenStore);//令牌存储策略

        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
        service.setTokenEnhancer(tokenEnhancerChain);

        service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
        service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
        return service;
    }
}

第二步: 认证服务会将WebSecurityConfig配置类中配置的用户身份信息和令牌其他的相关信息写入JWT令牌

@Bean
public UserDetailsService userDetailsService() {
    // 1. 配置用户信息服务
    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
    // 2. 创建用户信息这里暂时写死,后面需要从数据库中动态查询, Kyle的权限是p1,Lucy的权限是p2
    // User是Spring Security提供的工具类
    manager.createUser(User.withUsername("Kyle").password("123").authorities("p1").build());
    manager.createUser(User.withUsername("Lucy").password("456").authorities("p2").build());
    return manager;
}

第三步: 重启认证服务,使用HttpClient通过密码模式指定用户的身份信息申请令牌

# 密码模式
POST {{auth_host}}/auth/oauth/token?client_id=XcWebApp&client_secret=XcWebApp&grant_type=password&username=Kyle&password=123

第四步: 查看响应的Jwt令牌

响应参数描述
access_token生成的JWT令牌,用于客户端访问资源时使用
token_typebearer是在RFC6750中定义的一种token类型,在携带JWT访问资源时需要在head中加入bearer jwt令牌内容
refresh_token当JWT令牌快过期时使用刷新令牌可以再次生成JWT令牌
expires_in过期时间(秒)
scope令牌的权限范围,服务端可以根据令牌的权限范围去对令牌授权
jti令牌的唯一表示
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsieHVlY2hlbmctcGx1cyJdLCJ1c2VyX25hbWUiOiJLeWxlIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTY3ODQyNzQ5NiwiYXV0aG9yaXRpZXMiOlsicDEiXSwianRpIjoiY2IyOTI0ZjYtOGZiOS00N2ViLThjNGEtMWFmMjkzZWU4NTg4IiwiY2xpZW50X2lkIjoiWGNXZWJBcHAifQ.aVZOsHBEuowof41HgV2auyDrRh9ZiNfwn4qoQWjla7o",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsieHVlY2hlbmctcGx1cyJdLCJ1c2VyX25hbWUiOiJLeWxlIiwic2NvcGUiOlsiYWxsIl0sImF0aSI6ImNiMjkyNGY2LThmYjktNDdlYi04YzRhLTFhZjI5M2VlODU4OCIsImV4cCI6MTY3ODY3OTQ5NiwiYXV0aG9yaXRpZXMiOlsicDEiXSwianRpIjoiNjFhNWRmOGItZTc3ZS00YmVkLWE3OTQtZTlmMjJkM2FmMTYyIiwiY2xpZW50X2lkIjoiWGNXZWJBcHAifQ.JqEL9V4Yn8tWYtvH46wtbAgJQ1dEoseuWyQhDdZNveo",
"expires_in": 7199,
"scope": "all",
"jti": "cb2924f6-8fb9-47eb-8c4a-1af293ee8588"
}

第五步: 通过check_token接口校验响应的JWT令牌即解析令牌中的信息

// 校验JWT令牌
POST {{auth_host}}/auth/oauth/check_token?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsieHVlY2hlbmctcGx1cyJdLCJ1c2VyX25hbWUiOiJLeWxlIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTY3ODQyOTg5MywiYXV0aG9yaXRpZXMiOlsicDEiXSwianRpIjoiMzNhMzg4YWMtNzNmYS00ODBmLWEzMWUtOTdmOTJmMjBkNWZkIiwiY2xpZW50X2lkIjoiWGNXZWJBcHAifQ.cTcfIzL2avSp2XEsPvGU2IoJ060ooln1hARZCrvCxp4

// 响应结果
{
  "aud": [
    "xuecheng-plus"
  ],
  "user_name": "Kyle",
  "scope": [
    "all"
  ],
  "active": true,
  "exp": 1678429893,
  "authorities": [
    "p1"
  ],
  "jti": "33a388ac-73fa-480f-a31e-97f92f20d5fd",
  "client_id": "XcWebApp"
}

测试资源服务自行校验令牌

本项目各个微服务就是资源服务,如当客户端申请到JWT令牌后可以携带JWT令牌去内容管理服务查询课程信息,此时内容管理服务需要对携带的JWT令牌进行校验

在这里插入图片描述

第一步: 在内容管理服务的content-api工程中添加依赖spring-cloud-starter-securityspring-cloud-starter-oauth2

<!--认证相关-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

第二步: 在内容管理服务的content-api工程中添加配置类TokenConfig配置令牌的校验和存储策略

@Configuration
public class TokenConfig {
    private String SIGNING_KEY = "mq123";
	
    // 使用密钥校验令牌
    @Bean
    public JwtAccessTokenConverter accessTokenConverter(){
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(SIGNING_KEY);
        return converter;
    }
	
    // 存储令牌
    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }
}

第三步: 添加资源服务配置类ResourceServerConfig,添加需要进行身份认证后才能访问的URL即对访问的资源进行安全控制,只有携带jwt令牌且签证通过后才能访问

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    public static  final  String RESOURCE_ID = "xuecheng-plus";
	// Jwt令牌
    @Autowired
    TokenStore tokenStore;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID)
            .tokenStore(tokenStore)
            .stateless(true);
    }

    @Override 
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable() // 禁用CSRF保护
            .authorizeRequests() // 配置对请求的授权策略
            .antMatchers("/r/**", "/course/**").authenticated() // 指定以"/r/"和"/course/"开头的请求路径需要进行身份认证才能访问
            .anyRequest().permitAll();  // 允许其他所有请求即除了以上的请求不需要进行身份认证就可以访问
    }
}

第四步: 重启内容管理服务,使用HttpClient直接访问内容管理服务的接口(资源)并查看响应结果

# 直接根据课程id查询课程基本信息
GET {{content_host}}/content/course/22
Content-Type: application/json

# 响应结果
{
"error": "unauthorized",# 未认证
"error_description": "Full authentication is required to access this resource"
}	

第五步: 申请令牌然后携带认证服务颁发的JWT令牌访问内容管理服务的接口,在请求头中添加Authorization,内容为Bearer Jwt令牌,Bearer用于通过oauth2.0协议访问资源

###### 首先通过密码模式访问认证服务获取Jwt令牌,令牌中存储的是当前用户的身份信息
POST {{auth_host}}/auth/oauth/token?client_id=XcWebApp&client_secret=XcWebApp&grant_type=password&username=Kyle&password=123


# 携带正确的JWT令牌访问内容管理服务中的资源
GET {{content_host}}/content/course/160
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsieHVlY2hlbmctcGx1cyJdLCJ1c2VyX25hbWUiOiJLeWxlIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTY3ODQzOTMwOSwiYXV0aG9yaXRpZXMiOlsicDEiXSwianRpIjoiNTAxNDNiZTItOGM3ZC00MmUzLWEwNDMtMTQwMGQ5NWQ5MmZiIiwiY2xpZW50X2lkIjoiWGNXZWJBcHAifQ.o3nWLeRkJncEnnZ0egFmBpyC8Keq-L8IY6k0Uc0a96c

{
"id": 160,
"companyId": 1232141425,
"companyName": null,
"name": "猫片",
......
}

# 如果没有携带jwt令牌或内容错误则报令牌无效的错误
{
"error": "invalid_token",
"error_description": "Cannot convert access token to JSON"
}

获取令牌中存储的用户身份信息

客户端携带JWT令牌访问资源服务时, 由于JWT令牌中记录了用户身份信息,资源服务校验签名通过后将Header(令牌类型)和Payload(有效信息)两部分内容还原

  • 资源服务会取出用户的身份信息后然后将用户身份信息放在SecurityContextHolder上下文中
  • SecurityContext会与当前线程进行绑定,方便程序员在接口中获取用户信息

在查询课程的接口中添加获取用户身份信息的业务,重启内容管理服务查看控制台是否会输出申请该令牌的用户身份信息

    @ApiOperation("根据课程id查询课程基础信息")
    @GetMapping("/course/{courseId}")
    public CourseBaseInfoDto getCourseBaseById(@PathVariable Long courseId) {
        // 获取当前用户的身份
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        // 当前用户身份为:Kyle
        System.out.println("当前用户身份为:" + principal);
        return courseBaseInfoService.getCourseBaseInfo(courseId);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/275156.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【每日一题】【12.24】 - 【12.28】

&#x1f525;博客主页&#xff1a; A_SHOWY&#x1f3a5;系列专栏&#xff1a;力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 本周总结&#xff1a;本周的每日一题比较针对于数学问题的一个应用&#xff0c;如二元一次方程组的求解或者数组求和&#xff0c;同…

53.网游逆向分析与插件开发-游戏反调试功能的实现-通过内核信息检测调试器

码云地址&#xff08;master分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/sro_-ex.git 码云版本号&#xff1a;b44fddef016fc1587eda40ca7f112f02a8289504 代码下载地址&#xff0c;在 SRO_EX 目录下&#xff0c;文件名为&#xff1a;SRO_Ex-通过内核信息…

京东商家数据工具讲解(一):竞品数据如何监控与分析

京东平台的店铺众多&#xff0c;同行数不胜数。作为商家&#xff0c;如果连自己竞争对手的情况都不知道的话&#xff0c;很难在这个平台存活下去。那么&#xff0c;这次鲸参谋就来重点说一下“竞品分析”。 竞品分析&#xff0c;主要是对京东店铺运营期间竞争对手的市场经营状…

Next Station of Flink CDC

摘要&#xff1a;本文整理自阿里云智能 Flink SQL、Flink CDC 负责人伍翀&#xff08;花名&#xff1a;云邪&#xff09;&#xff0c;在 Flink Forward Asia 2023 主会场的分享。Flink CDC 是一款基于 Flink 打造一系列数据库的连接器。本次分享主要介绍 Flink CDC 开源社区在过…

Linux安装GitLab教程

Linux安装GitLab教程 1、配置yum源 相当于新建一个文件&#xff0c;通过这个文件来安装gitlab vim /etc/yum.repos.d/gitlab-ce.repo 把这些配置粘进去 [gitlab-ce] nameGitlab CE Repository baseurlhttps://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el$releasever/ gp…

K8s实战-init容器

概念&#xff1a; 初始化容器的概念 比如一个容器A依赖其他容器&#xff0c;可以为A设置多个 依赖容易A1&#xff0c;A2&#xff0c;A3 A1,A2,A3要按照顺序启动&#xff0c;A1没有启动启动起来的 话&#xff0c;A2,A3是不会启动的&#xff0c;直到所有的静态容器全 部启动完毕…

Flink项目实战篇 基于Flink的城市交通监控平台(下)

系列文章目录 Flink项目实战篇 基于Flink的城市交通监控平台&#xff08;上&#xff09; Flink项目实战篇 基于Flink的城市交通监控平台&#xff08;下&#xff09; 文章目录 系列文章目录4. 智能实时报警4.1 实时套牌分析4.2 实时危险驾驶分析4.3 出警分析4.4 违法车辆轨迹跟…

hive在执行elect count(*) 没有数据显示为0(实际有数据)

set hive.compute.query.using.statsfalse; 是 Hive 的一个配置选项。它的含义是禁用 Hive 在执行查询时使用统计信息。 在 Hive 中&#xff0c;统计信息用于优化查询计划和执行。当该选项设置为 false 时&#xff0c;Hive 将不会使用任何统计信息来帮助决定查询的执行计划。这…

Flink1.17实战教程(第六篇:容错机制)

系列文章目录 Flink1.17实战教程&#xff08;第一篇&#xff1a;概念、部署、架构&#xff09; Flink1.17实战教程&#xff08;第二篇&#xff1a;DataStream API&#xff09; Flink1.17实战教程&#xff08;第三篇&#xff1a;时间和窗口&#xff09; Flink1.17实战教程&…

《深入理解Java虚拟机(第三版)》读书笔记:虚拟机类加载机制、虚拟机字节码执行引擎、编译与优化

下文是阅读《深入理解Java虚拟机&#xff08;第3版&#xff09;》这本书的读书笔记&#xff0c;如有侵权&#xff0c;请联系删除。 文章目录 第6章 类文件结构第7章 虚拟机类加载机制7.2 类加载的时机7.3 类加载的过程7.4 类加载器7.5 Java模块化系统 第8章 虚拟机字节码执…

Redis 核心知识总结

Redis 核心知识总结 认识 Redis 什么是 Redis&#xff1f; Redis 是一个由 C 语言开发并且基于内存的键值型数据库&#xff0c;对数据的读写操作都是在内存中完成&#xff0c;因此读写速度非常快&#xff0c;常用于缓存&#xff0c;消息队列、分布式锁等场景。 有以下几个特…

web三层架构

目录 1.什么是三层架构 2.运用三层架构的目的 2.1规范代码 2.2解耦 2.3代码的复用和劳动成本的减少 3.各个层次的任务 3.1web层&#xff08;表现层) 3.2service 层(业务逻辑层) 3.3dao 持久层(数据访问层) 4.结合mybatis简单实例演示 1.什么是三层架构 三层架构就是把…

Node.js--》node环境配置及nvm和nvm-desktop安装教程

博主最近换了台新电脑&#xff0c;环境得从零开始配置&#xff0c;所以以下是博主从一台纯净机中配置环境&#xff0c;绝对的小白教程&#xff0c;大家第一次安装完全可以参考我的过程&#xff0c;闲话少说&#xff0c;直接开始&#xff01;&#xff01;&#xff01; 接下来介绍…

Linux下安装QQ

安装步骤&#xff1a; 1.进入官网&#xff1a;QQ Linux版-轻松做自己 2.选择版本&#xff1a;X86版下载dep 3安装qq 找到qq安装包位置&#xff0c;然后右击在终端打开输入安装命令&#xff0c;然后点击回车 sudo dpkg -i linuxqq_3.2.0-16736_amd64.deb 卸载qq 使用命令…

如何使用Linux docker方式快速安装Plik并结合内网穿透实现公网访问

文章目录 1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设备上传或者…

ALSA学习(4)——Control设备的创建

参考博客&#xff1a; https://blog.csdn.net/DroidPhone/article/details/6409983 &#xff08;下面的内容基本是原博主的内容&#xff0c;我只是修改了一些格式之类的&#xff09; 文章目录 一、Control接口二、Controls的定义三、Control的名字四、访问标志&#xff08;ACC…

C# NLua Winform 热更新

一、概述 NLua 是一个用于 .NET 平台的 Lua 脚本绑定库。它允许在 C# 代码中嵌入 Lua 脚本&#xff0c;并允许两者之间进行交互。NLua 的主要特点包括&#xff1a; 轻量级&#xff1a;NLua 是一个轻量级的库&#xff0c;易于集成到现有的 .NET 项目中。动态类型&#xff1a;L…

2024年【裂解(裂化)工艺】考试报名及裂解(裂化)工艺考试总结

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 裂解&#xff08;裂化&#xff09;工艺考试报名考前必练&#xff01;安全生产模拟考试一点通每个月更新裂解&#xff08;裂化&#xff09;工艺考试总结题目及答案&#xff01;多做几遍&#xff0c;其实通过裂解&#…

Tuxera NTFS for Mac2024免费Mac读写软件下载教程

在日常生活中&#xff0c;我们使用Mac时经常会遇到外部设备不能正常使用的情况&#xff0c;如&#xff1a;U盘、硬盘、软盘等等一系列存储设备&#xff0c;而这些设备的格式大多为NTFS&#xff0c;Mac系统对NTFS格式分区存在一定的兼容性问题&#xff0c;不能正常读写。 那么什…

如何从 DSA 切换到 PMax 以使您的 Google 付费广告面向未来

为了在 Google Ads 不可避免的过渡期之前&#xff0c;我们将介绍如何从动态搜索广告切换到效果最大化广告 如何从 DSA 切换到 PMax 以使您的 Google 付费广告面向未来 变化是唯一不变的&#xff0c;尤其是在数字广告中——您可能听说过一些关于动态搜索广告 &#xff08;DSA&…