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";@AutowiredTokenStore tokenStore;@Autowiredprivate JwtAccessTokenConverter accessTokenConverter;@Beanpublic TokenStore tokenStore() {// 采用Jwt的方式存储令牌return new JwtTokenStore(accessTokenConverter());}// Jwt令牌转换器@Beanpublic 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";// 使用密钥校验令牌@Beanpublic JwtAccessTokenConverter accessTokenConverter(){JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(SIGNING_KEY);return converter;}// 存储令牌@Beanpublic 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令牌@AutowiredTokenStore tokenStore;@Overridepublic 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();// 当前用户身份为:KyleSystem.out.println("当前用户身份为:" + principal);return courseBaseInfoService.getCourseBaseInfo(courseId);}

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud(H版alibaba)框架开发教程---附源码 一

源码地址&#xff1a;https://gitee.com/jackXUYY/springboot-example 创建订单服务&#xff0c;支付服务&#xff0c;公共api服务&#xff08;共用的实体&#xff09;&#xff0c;eureka服务 1.cloud-consumer-order80 2.cloud-provider-payment8001 3.cloud-api-commons 4.…

国标标准和行业标准使用介绍

场景 我现在所在行业是交通行业&#xff0c;主要做城市交通信控相关的工作&#xff0c;后续可能会涉及高速、收费站、稽核收费等业务场景在做产品开发时&#xff0c;我们需要有一个标准可以参考&#xff0c;这些标准必须是公认的&#xff0c;这时就用到了 国家标准、行业标准等…

仓储革新:AR技术引领物流进入智慧时代

根据《2022年中国物流行业研究&#xff1a;深度探析行业现状&#xff08;智能设备及智能软件&#xff09;》&#xff0c;报告中提及&#xff1a;“中国社会物流总额依然保持着较为良好的增长态势&#xff0c;年增速已恢复至常年平均水平。2021年社会物流总额细分中工业物流总额…

有没有什么软件可以用来线上走审批流程的?

有没有什么软件可以用来线上走审批流程的&#xff1f; 这就不得不提一嘴我们简道云了——因为&#xff0c;用简道云来搭建审批流程是特别“省”的&#xff1a; 省沟通&#xff1a;不用费心费力跟外部开发者沟通需求&#xff0c;自己动手做一点试一点&#xff1b; 省时间&…

数据通信基础知识

消息和信息、信号和数据 消息和信息 通信是在源点与终点之间传递消息或者信息。 信息和消息有着不同的概念。 消息是指能向人们表达客观物质运动和主观思维活动的文字、符号、数据、语音和图像等。它有两个特点: 能被通信双方所理解可以相互传递。 信息是指包含在消息中对通…

JOSEF约瑟 双位置继电器 DCS-12/110V 线圈电压直流110V 板前安装

系列型号&#xff1a; DCS-11双位置继电器&#xff1b; DCS-12双位置继电器&#xff1b; DCS-13双位置继电器&#xff1b; RXMVB2 RK 251 204双位置继电器&#xff1b; RXMVB2 RK 251 205双位置继电器&#xff1b; RXMVB2 RK 251 106双位置继电器&#xff1b; 一、用途 …

本地缓存:Caffeine入门使用

概况 回顾互联网应用发展史&#xff0c;可以发现一个通用并且普遍存在的一个工作过程。如下图所示&#xff0c;用户从浏览器发出请求 -> 网络转发请求 -> 应用服务业务处理 -> 底层存储信息获取&#xff0c;然后逆向的返回用户&#xff0c;形成页面给予用户相应信息。…

[递归回溯枚举] 装载问题

装载问题 题目描述 有一批共 n 个集装箱要装上 2 艘载重量分别为 c1和 c2的轮船&#xff0c;其中集装箱 i 的重量为 wi&#xff0c;且 装载问题要求确定&#xff0c;是否有一个合理的装在方案可将这 n 个集装箱装上这 2 艘轮船。如果有&#xff0c;找出最优装载方案。 关于输…

【idea】运行工程时候卡了许久Java Method Breakpoints

老以为是数据库连接不上&#xff0c;此问题概率性小&#xff0c;操作上面不小心打了断点… 应该是打断点的时候&#xff0c;打到了方法上面&#xff0c;去掉哟 Java Method Breakpoints

文件过大放不了U盘?三个方法非常简单~

文件过大放不了U盘我们可以从文件过大这个角度来解决一下这个问题&#xff0c;可以借助一些工具把文件压缩后&#xff0c;体积变小后&#xff0c;再放入U盘&#xff0c;使得u盘得到高效的利用&#xff0c;下面是推荐的一些好用的软件。 一、嗨格式压缩大师 是一款可以压缩多种…

干货!一文详解车间管理的五大基本方法

车间管理是制造型企业生产过程中的重要环节&#xff0c;它直接影响着企业的生产效率、成本控制、产品质量以及员工的士气与工作效率。优秀的车间管理不仅能够提升产品的质量和生产力&#xff0c;还能降低运营成本&#xff0c;从而在激烈的市场竞争中为企业赢得优势。 为了帮助…

1.3MySQL中的自连接

自己的表和自己连接&#xff0c;核心&#xff1a;一张表拆为两张一样的表。 语法&#xff1a;select 字段列表 from 表 [as] 表别名1,表 [as] 表别名2 where 条件...; 关于怎样把一个表拆分成一个表&#xff0c;只要给它们分别取别名就行 categoryidpidcategoryname21信息…

ai写作生成器哪个好用?值得推荐这几款

随着人工智能技术的不断发展&#xff0c;AI写作生成器逐渐成为了写作领域的新宠。这些软件利用机器学习和自然语言处理等技术&#xff0c;能够自动生成高质量的文章&#xff0c;为写作者提供了极大的便利。在国内&#xff0c;也涌现出了许多优秀的AI写作软件。本文将介绍几款国…

16-网络安全框架及模型-BiBa完整性模型

目录 BiBa完整性模型 1 背景概述 2 模型原理 3 主要特性 4 优势和局限性 5 应用场景 BiBa完整性模型 1 背景概述 Biba完整性模型是用于保护数据完整性的模型&#xff0c;它的主要目标是确保数据的准确性和一致性&#xff0c;防止未授权的修改和破坏。在这个模型中&#…

事务的简介

一、什么是事务 事务是一组数据库的操作序列&#xff0c;包含一个或多个sql操作命令&#xff08;增删改&#xff09;&#xff0c;事务将所有的操作命令看做一个不可分割的整体&#xff0c;向数据库系统提交或撤销操作&#xff0c;所有操作要么执行要么不执行。 ●事务是一种机…

Apache OFBiz RCE漏洞复现(CVE-2023-51467)

0x01 产品简介 Apache OFBiz是一个电子商务平台,用于构建大中型企业级、跨平台、跨数据库、跨应用服务器的多层、分布式电子商务类应用系统。 0x02 漏洞概述 漏洞成因 该系统的身份验证机制存在缺陷,可能允许未授权用户通过绕过标准登录流程来获取后台访问权限。此外,在…

如何借助边缘网关打造智慧配电房安全方案

配电房是电力系统的重要组成部分&#xff0c;通常设置有各种高压配电装置和箱柜&#xff0c;是企业安全管理的重点。传统的人工巡检和监控总是难以避免疏漏&#xff0c;导致风险隐患的产生和扩大。 随着物联网、边缘计算、设备联动控制等技术的普及应用&#xff0c;佰马针对配电…

消费升级:如何通过服务升级吸引消费者

在当今竞争激烈的市场环境中&#xff0c;企业必须不断创新和改进&#xff0c;以吸引和留住消费者。其中&#xff0c;升级服务已成为企业提升竞争力的重要手段。本文将通过分析一家成功通过升级服务吸引消费者的企业&#xff0c;探讨其背后的策略和经验。 这家企业以其卓越的服务…

原生微信小程序如何动态配置主题颜色及如何调用子组件的方法

一、最终效果 二、步骤 1、在初始化进入项目时&#xff0c;获取当前主题色 2、把主题色定义成全局变量&#xff08;即在app.js中设置&#xff09; 3、tabBar也需要定义全局变量&#xff0c;在首页时需要重新赋值 三、具体实现 1、app.js onLaunch () {//获取主题数据this.set…