JWT令牌生成与校验
目录
- 1 JWT介绍
- 1.1 什么是JWT?
- 1.2 JWT令牌结构
- 2 配置JWT令牌服务
- 3 生成JWT令牌
- 4 校验JWT令牌
- 5 JWT整合Spring Security
- 5.1 创建表
- 6 配置授权服务
- 6.1 测试
1 JWT介绍
通过上边的测试我们发现,当资源服务和授权服务不在一起时资源服务使用RemoteTokenServices 远程请求授权服务验证token,如果访问量较大将会影响系统的性能 。
解决上边问题:
令牌采用JWT格式即可解决上边的问题,用户认证通过会得到一个JWT令牌,JWT令牌中已经包括了用户相关的信息,客户端只需要携带JWT访问资源服务,资源服务根据事先约定的算法自行完成令牌校验,无需每次都请求认证服务完成授权。
1.1 什么是JWT?
JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简介的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公钥/私钥对来签名,防止被篡改。
官网:JWT.IO
标准: JSON Web Token (JWT)
JWT令牌的优点:
1)jwt基于json,非常方便解析。
2)可以在令牌中自定义丰富的内容,易扩展。
3)通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。
4)资源服务使用JWT可不依赖认证服务即可完成授权。
缺点:
1)JWT令牌较长,占存储空间比较大。
1.2 JWT令牌结构
通过学习JWT令牌结构为自定义jwt令牌打好基础。
JWT令牌由三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz
- Header
头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA)
一个例子如下:
下边是Header部分的内容
{ "alg": "HS256","typ": "JWT"
}
将上边的内容使用Base64Url编码,得到一个字符串就是JWT令牌的第一部分。
- Payload
第二部分是负载,内容也是一个json对象,它是存放有效信息的地方,它可以存放jwt提供的现成字段,比如:iss(签发者),exp(过期时间戳), sub(面向的用户)等,也可自定义字段。
此部分不建议存放敏感信息,因为此部分可以解码还原原始内容。
最后将第二部分负载使用Base64Url编码,得到一个字符串就是JWT令牌的第二部分。
一个例子:
{ "sub": "1234567890","name": "456","admin": true
}
- Signature
第三部分是签名,此部分用于防止jwt内容被篡改。
这个部分使用base64url将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用header中声明签名算法进行签名。
一个例子:
HMACSHA256( base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
base64UrlEncode(header):jwt令牌的第一部分。
base64UrlEncode(payload):jwt令牌的第二部分。
secret:签名所使用的密钥。
2 配置JWT令牌服务
在uaa中配置jwt令牌服务,即可实现生成jwt格式的令牌。
1、TokenConfig
@Configuration
public class TokenConfig {private String SIGNING_KEY = "uaa123";@Beanpublic TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());}@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(SIGNING_KEY); //对称秘钥,资源服务器使用该秘钥来验证return converter;}
}
2、定义JWT令牌服务
@Autowired
private JwtAccessTokenConverter accessTokenConverter;@Beanpublic AuthorizationServerTokenServices tokenService() {DefaultTokenServices service=new DefaultTokenServices();service.setClientDetailsService(clientDetailsService);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;}
3 生成JWT令牌
响应:
4 校验JWT令牌
资源服务需要和授权服务拥有一致的签字、令牌服务等:
1、将授权服务中的TokenConfig类拷贝到资源 服务中
2、屏蔽资源 服务原来的令牌服务类
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResouceServerConfig extendsResourceServerConfigurerAdapter {public static final String RESOURCE_ID = "res1";@AutowiredTokenStore tokenStore;//资源服务令牌解析服务
// @Bean
// public ResourceServerTokenServices tokenService() {// //使用远程服务请求授权服务器校验token,必须指定校验token 的url、client_id,client_secret
// RemoteTokenServices service=new RemoteTokenServices();
// service.setCheckTokenEndpointUrl("http://localhost:53020/uaa/oauth/check_token");
// service.setClientId("c1");
// service.setClientSecret("secret");
// return service;
// }@Overridepublic void configure(ResourceServerSecurityConfigurer resources) {resources.resourceId(RESOURCE_ID).tokenStore(tokenStore).stateless(true);}
3、测试
1)申请jwt令牌
2)使用令牌请求资源
小技巧:
令牌申请成功可以使用/uaa/oauth/check_token校验令牌的有效性,并查询令牌的内容,例子如下:
5 JWT整合Spring Security
截止目前客户端信息和授权码仍然存储在内存中,生产环境中通过会存储在数据库中,下边完善环境的配置:
5.1 创建表
在user_db中创建如下表:
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (`client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '客户端标
识',`resource_ids` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
COMMENT '接入资源列表',`client_secret` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
COMMENT '客户端秘钥',`scope` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`authorized_grant_types` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT
NULL,`web_server_redirect_uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT
NULL,`authorities` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`access_token_validity` int(11) NULL DEFAULT NULL,`refresh_token_validity` int(11) NULL DEFAULT NULL,`additional_information` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL,`create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE
CURRENT_TIMESTAMP(0),`archived` tinyint(4) NULL DEFAULT NULL,`trusted` tinyint(4) NULL DEFAULT NULL,`autoapprove` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,PRIMARY KEY (`client_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '接入客户端信息'
ROW_FORMAT = Dynamic;
INSERT INTO `oauth_client_details` VALUES ('c1', 'res1',
'$2a$10$NlBC84MVb7F95EXYTXwLneXgCca6/GipyWR5NHm8K0203bSQMLpvm', 'ROLE_ADMIN,ROLE_USER,ROLE_API',
'client_credentials,password,authorization_code,implicit,refresh_token', 'http://www.baidu.com',
NULL, 7200, 259200, NULL, '2019‐09‐09 16:04:28', 0, 0, 'false');
INSERT INTO `oauth_client_details` VALUES ('c2', 'res2',
'$2a$10$NlBC84MVb7F95EXYTXwLneXgCca6/GipyWR5NHm8K0203bSQMLpvm', 'ROLE_API',
'client_credentials,password,authorization_code,implicit,refresh_token', 'http://www.baidu.com',
NULL, 31536000, 2592000, NULL, '2019‐09‐09 21:48:51', 0, 0, 'false');
oauth_code表,Spring Security OAuth2使用,用来存储授权码:
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (`create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,`code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`authentication` blob NULL,INDEX `code_index`(`code`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
6 配置授权服务
(1)修改AuthorizationServer:
ClientDetailsService和AuthorizationCodeServices从数据库读取数据。
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends
AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter accessTokenConverter;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private AuthorizationCodeServices authorizationCodeServices;
@Autowired
private AuthenticationManager authenticationManager;
/** * 1.客户端详情相关配置 */
@Bean public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Bean
public ClientDetailsService clientDetailsService(DataSource dataSource) {
ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
((JdbcClientDetailsService)
clientDetailsService).setPasswordEncoder(passwordEncoder());return clientDetailsService;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.withClientDetails(clientDetailsService);
}
/** * 2.配置令牌服务(token services) */
@Bean
public AuthorizationServerTokenServices tokenService() {
DefaultTokenServices service=new DefaultTokenServices();
service.setClientDetailsService(clientDetailsService);
service.setSupportRefreshToken(true);//支持刷新令牌
service.setTokenStore(tokenStore); //绑定tokenStore
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
service.setTokenEnhancer(tokenEnhancerChain);
service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
return service;
}
/** * 3.配置令牌(token)的访问端点 */
@Bean
public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
return new JdbcAuthorizationCodeServices(dataSource);//设置授权码模式的授权码如何存取
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
.authorizationCodeServices(authorizationCodeServices)
.tokenServices(tokenService())
.allowedTokenEndpointRequestMethods(HttpMethod.POST);
}
/** * 4.配置令牌端点(Token Endpoint)的安全约束 */
@Override
public void configure(AuthorizationServerSecurityConfigurer security){
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()")
.allowFormAuthenticationForClients()//允许表单认证
;
}
}
6.1 测试
1、测试申请令牌
使用密码模式申请令牌,客户端信息需要和数据库中的信息一致。
POST http://localhost:53020/uaa/oauth/token
2、测试授权码模式
生成的授权存储到数据库中。
http://localhost:53020/uaa/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com
注意scope=?,查看数据库
POST http://localhost:53020/uaa/oauth/token
JWT令牌生成与校验相关推荐
- 从零开始超详细的Spring Security OAuth2.0实现分布式系统授权(注册中心+网关+认证授权服务(JWT令牌验证)+资源调用服务)
文章目录 一.OAuth2.0 1.介绍 2.例子 3.执行流程 二.Spring Cloud Security OAuth2 1.环境介绍 2.认证流程 三.整合分布式项目 1.技术方案 2.项目结 ...
- 十七.SpringCloud+Security+Oauth2实现微服务授权 -非对称加密生成JWT令牌
仅做学习使用,老鸟飞过,欢迎交流 前言 在之前的微服务授权方案<SpringCloud+Security+Oauth2实现微服务授权 - 授权服务配置>中我们使用的是Oauth+JWT方式 ...
- jwt令牌_JWT –生成和验证令牌–示例
jwt令牌 JWT提供了一种非常有趣的方式来表示可以验证和信任的应用程序之间的声明. 我的目标是展示一个小的样本,它使用出色的Nimbus JOSE + JWT库来生成和验证令牌. 总览 进行介绍的最 ...
- 在springboot中使用JWT自定义生成Token信息,接口请求时校验Token(在Shiro基础上)
前言 项目原有使用的是 springboot + shiro 的环境,后来由于应用要与OA对接单点登录,所以在原有基础上,修改成使用JWT自定义生成token信息和校验token功能. 实现思路 1. ...
- OAuth2.0 使用 JWT令牌
应用背景:当资源服务和认证服务不在一起时,资源服务使用RemoteTokenServices远程请求授权服务验证token,如果访问量较大较会影响系统的性能.这时可以考虑做进一步的优化,令牌采用JWT ...
- Day241242.单点登录方案【Jwt令牌、sessionredis、CAS认证服务器】 -springsecurity-jwt-oauth2
1.单点登录与状态共享方案 随着企业的应用规模不断增大,一个单体应用很难满足用户量增长的需求,这就需要我们将单体应用集群化部署,或者将单体应用微服务化.在这个过程中,就涉及到两个问题: 集群应用之间如 ...
- Shiro+JWT+Redis实现用户校验
Shiro基础知识 1. shiro基本功能 认证:验证用户登录认证: 授权:即权限验证,对已经登录的用户验证是否有相应的权限: 会话管理:用户在认证成功之后创建会话,当前用户的所有信息都会保存在这个 ...
- 畅购商城六:微服务网关与jwt令牌
微服务网关 基本概念 对于微服务的各个服务一般会有不同的地址,外部客户端的一个服务可能要调用诸多的接口,这会带来以下的问题 客户端会多次请求不同的微服务,地址复杂 存在跨域请求,处理复杂 认证复杂 难 ...
- Spring Cloud Feign如何实现JWT令牌中继以传递认证信息
在上一篇实现了Spring Cloud资源服务器的定制化,但是又发现了一个新的问题,Spring Cloud微服务调用的过程中需要令牌中继.只有令牌中继才能在调用链中保证用户认证信息的传递.今天就来分 ...
- JWT令牌创建和解析讲解
JJWT的介绍和使用 JJWT是一个提供端到端的JWT创建和验证的Java库.永远免费和开源(Apache License,版本2.0),JJWT很容易使用和理解.它被设计成一个以建筑为中心的流畅界面 ...
最新文章
- Wince 添加中文字库
- Linux:shell脚本中实现变量自增的几种方式
- Python安装教程分享
- 蛇形打印数组(某宝典公司面试手撕代码题)
- 史上最牛的文科生:法学出身,却发明出十进制计算器,折磨无数人的微积分符号,跨界40多个领域惊艳学术圈
- 解决: Gitee 自已提交的代码提交人头像为他人、码云上独自开发的项目显示为 2 个开发者
- 在ASP.NET 3.5中使用新的ListView控件(5)
- C++ 四种类型转换
- Mysql学习总结(34)——Mysql 彻底解决中文乱码的问题
- 两平面平行但不重合的条件是_____2012江苏省数学竞赛《提优教程》教案:第77讲_组合几何...
- Http网络传递参数中文乱码问题解决办法
- linux链接器脚本,vmlinux-lds 连接器脚本
- Camera:双目成像原理
- 开源扫描仪软件_适用于Windows的优秀开源免费扫描仪软件?
- 修改thinkpad 小红点(TrackPoint速度)
- 读书摘录---《李嘉诚成功语录 》
- kepware怎么读modbus/tcp数据_DDR3读写数据调试
- UE4 Pak包热更新
- ibm tivoli_Tivoli Access Manager信任关联拦截器(TAI ++)
- 大数据本科毕业论文应该怎么写?
热门文章
- 【转】MMORPG开发入门【强力推荐,写的很好】
- CRT团队组员博客地址统计
- 微信公众号上传图文素材thumb_media_id的获得
- 程序员女朋友都是在哪找的?
- Android 支付宝sdk接入问题:不能唤起支付宝客户端,或者偶然唤起支付客户端
- 汽车制造行业汽车电子,从哪里开始,你合适吗?
- 港科夜闻|香港科技大学(HKUST)及香港科大智能建造实验室(HKUST BIM Lab)荣获CIC建造数码化大奖组织类最高奖项...
- 语音识别(五)——Mel-Frequency Analysis, FBank, 语音识别的评价指标, 声学模型进阶
- 又是一年春来到,祝大家有个好的开始。
- 北京内推 | Hulu机器学习应用平台团队招聘推荐大数据方向暑期实习生