历史文章

[Spring Security OAuth2.0认证授权一:框架搭建和认证测试]
[Spring Security OAuth2.0认证授权二:搭建资源服务]

前面两篇文章详细讲解了如何基于spring boot + oath2.0搭建认证中心和资源中心,本篇文章将会讲解集成jwt以及将客户端信息和授权码信息保存到数据库。

一、 JWT

1. JWT简介

JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),它定义了一种简介的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公钥/私钥对来签名,防止被篡改。

官网:https://jwt.io/

标准: https://tools.ietf.org/html/rfc7519

JWT令牌的优点:

1)jwt基于json,非常方便解析。

2)可以在令牌中自定义丰富的内容,易扩展。

3)通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。

4)资源服务使用JWT可不依赖认证服务即可完成授权。

缺点:

1)JWT令牌较长,占存储空间比较大,这意味着会耗费一定的带宽资源

2)JWT签名和验签都要耗费处理器资源

2. JWT令牌结构

JWT令牌由三部分组成,每部分中间使用点(.)分隔,比如:xxxxx.yyyyy.zzzzz

2.1 Header

头部包括令牌的类型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA)一个例子如下:

下边是Header部分的内容

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

JSON

Copy

将上边的内容使用Base64Url编码,得到一个字符串就是JWT令牌的第一部分。

2.2 Payload

第二部分是负载,内容也是一个json对象,它是存放有效信息的地方,它可以存放jwt提供的现成字段,比如:iss(签发者),exp(过期时间戳), sub(面向的用户)等,也可自定义字段。此部分不建议存放敏感信息,因为此部分可以解码还原原始内容。最后将第二部分负载使用Base64Url编码,得到一个字符串就是JWT令牌的第二部分。

一个例子:

{
"sub": "1234567890",
"name": "456",
"admin": true
}

JSON

Copy

2.3 Signature

第三部分是签名,此部分用于防止jwt内容被篡改。

这个部分使用base64url将前两部分进行编码,编码后使用点(.)连接组成字符串,最后使用header中声明签名算法进行签名。

一个例子:

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

Java

Copy

  • base64UrlEncode(header):jwt令牌的第一部分。
  • base64UrlEncode(payload):jwt令牌的第二部分。
  • secret:签名所使用的密钥。

二、配置JWT

1.认证服务配置JWT

TokenConfig类的修改

@Configuration
public class TokenConfig {private static final String SIGNING_KEY = "auth123";@Bean
public TokenStore tokenStore() {return new JwtTokenStore(accessTokenConverter());
}@Bean
public JwtAccessTokenConverter accessTokenConverter(){JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey(SIGNING_KEY);//对称秘钥,资源服务器使用该秘钥来验证
return jwtAccessTokenConverter;
}
}

Java

Copy

AuthorizationServerTokenServices设置Token增强类

    @Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;@Bean
public AuthorizationServerTokenServices tokenServices(){DefaultTokenServices services = new DefaultTokenServices();
services.setClientDetailsService(clientDetailsService);
services.setSupportRefreshToken(true);
services.setTokenStore(tokenStore);
services.setAccessTokenValiditySeconds(7200);
services.setRefreshTokenValiditySeconds(259200);TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Collections.singletonList(jwtAccessTokenConverter));
services.setTokenEnhancer(tokenEnhancerChain);return services;
}

Java

Copy

然后就可以测试了:

POST请求接口:http://127.0.0.1:30000/oauth/token?client_id=c1&client_secret=secret&grant_type=password&username=zhangsan&password=123

得到响应结果:

{"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJ6aGFuZ3NhbiIsInNjb3BlIjpbIlJPTEVfQURNSU4iLCJST0xFX1VTRVIiLCJST0xFX0FQSSJdLCJleHAiOjE2MTAzNzI5MzUsImF1dGhvcml0aWVzIjpbInAxIiwicDIiXSwianRpIjoiOWQzMzRmZGMtOTcwZC00YmJkLWI2MmMtZDU4MDZkNTgzM2YwIiwiY2xpZW50X2lkIjoiYzEifQ.gZraRNeX-o_jKiH7XQgg3TlUQBpxUcXa2-qR_Treu8U",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJ6aGFuZ3NhbiIsInNjb3BlIjpbIlJPTEVfQURNSU4iLCJST0xFX1VTRVIiLCJST0xFX0FQSSJdLCJhdGkiOiI5ZDMzNGZkYy05NzBkLTRiYmQtYjYyYy1kNTgwNmQ1ODMzZjAiLCJleHAiOjE2MTA2MjQ5MzUsImF1dGhvcml0aWVzIjpbInAxIiwicDIiXSwianRpIjoiN2U1NzE0NTgtNmU2Zi00YjlmLTkxODQtOWUzZmVmZmQ1YTNjIiwiY2xpZW50X2lkIjoiYzEifQ.wyiS-z-xhBPZSODXZHQVDJCQ6dcmeJjAwBPWe2GhT94",
"expires_in": 7199,
"scope": "ROLE_ADMIN ROLE_USER ROLE_API",
"jti": "9d334fdc-970d-4bbd-b62c-d5806d5833f0"
}

JSON

Copy

会发现accessToken长了很多,这是因为token是jwt字符串,分为三部分,第二部分payload携带了很多信息,打开jwt.io网站,将上面的accessToken贴上去,可以看到Base64解码后的信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QLTUSpTD-1661928796489)(/storage/thumbnails/_signature/2B8J8S7BH0UB15MRJNP45M1G6J.png)]

2.资源服务配置

第一步,将认证服务中的TokenConfig直接拷贝到资源服务中

第二步,修改ResouceServerConfig 类

    @Autowired
private TokenStore tokenStore;@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {resources
.resourceId(RESOURCE_ID)
//                .tokenServices(resourceServerTokenServices)//令牌服务
.tokenStore(tokenStore)
.stateless(true);
}

Java

Copy

即可完成资源服务集成jwt的功能。

3.接口测试

POST请求 http://127.0.0.1:30000/oauth/token?client_id=c1&client_secret=secret&grant_type=password&username=zhangsan&password=123 获取令牌,获取到accessToken之后携带token GET 请求 http://127.0.0.1:30001/r1 ,得到响应结果:

访问资源r1

Txt

Copy

即可证明成功。

三、客户端信息保存到数据库

认证服务客户端信息还是保存在内存中,现在将其改造放到数据库中

1. 新建表

DROP TABLE IF EXISTS `oauth_client_details`;CREATE TABLE `oauth_client_details` (
`client_id` varchar(255) NOT NULL COMMENT '客户端标识',
`resource_ids` varchar(255) DEFAULT NULL COMMENT '接入资源列表',
`client_secret` varchar(255) DEFAULT NULL COMMENT '客户端秘钥',
`scope` varchar(255) DEFAULT NULL,
`authorized_grant_types` varchar(255) DEFAULT NULL,
`web_server_redirect_uri` varchar(255) DEFAULT NULL,
`authorities` varchar(255) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` longtext,
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`archived` tinyint(4) DEFAULT NULL,
`trusted` tinyint(4) DEFAULT NULL,
`autoapprove` varchar(255) DEFAULT NULL,
PRIMARY KEY (`client_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='接入客户端信息';/*Data for the table `oauth_client_details` */insert  into `oauth_client_details`(`client_id`,`resource_ids`,`client_secret`,`scope`,`authorized_grant_types`,`web_server_redirect_uri`,`authorities`,`access_token_validity`,`refresh_token_validity`,`additional_information`,`create_time`,`archived`,`trusted`,`autoapprove`) values
('c1','res1','$2a$10$X2xVwW.7cOEh2niPqHYAne9EnjRJFj7QI4TqfmnDou9fT/45sCFEm','ROLE_ADMIN,ROLE_USER,ROLE_API','client_credentials,password,authorization_code,implicit,refresh_token','https://www.baidu.com',NULL,7200,259200,NULL,'2021-01-11 09:09:53',0,0,'false'),
('c2','res2','$2a$10$X2xVwW.7cOEh2niPqHYAne9EnjRJFj7QI4TqfmnDou9fT/45sCFEm','ROLE_API','client_credentials,password,authorization_code,implicit,refresh_token','https://www.baidu.com',NULL,31536000,2592000,NULL,'2021-01-11 09:09:56',0,0,'false');/*Table structure for table `oauth_code` */DROP TABLE IF EXISTS `oauth_code`;CREATE TABLE `oauth_code` (
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`code` varchar(255) DEFAULT NULL,
`authentication` blob,
KEY `code_index` (`code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

SQL

Copy

上述SQL新建了两张表oauth_client_details以及oauth_code分别用于存储客户端信息以及授权码信息,由于使用了jwt token(jwt token本身就存储了数据),所以不再保存数据库,两张表均为spring oauth2.0内置表,不需要写SQL,内置框架自动识别表。

2.修改配置

对应上述两张表,分别修改Bean对象的创建为jdbc类型的:

    @Bean
public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource){return new JdbcAuthorizationCodeServices(dataSource);
}@Bean
public ClientDetailsService clientDetailsService(DataSource dataSource) {JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
clientDetailsService.setPasswordEncoder(passwordEncoder);
return clientDetailsService;
}

Java

Copy

之后修改客户端配置对象:

    @Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.withClientDetails(clientDetailsService);
//        clients.inMemory()
//                .withClient("c1")
//                .secret(new BCryptPasswordEncoder().encode("secret"))//$2a$10$0uhIO.ADUFv7OQ/kuwsC1.o3JYvnevt5y3qX/ji0AUXs4KYGio3q6
//                .resourceIds("r1")
//                .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
//                .scopes("all")
//                .autoApprove(false)
//                .redirectUris("https://www.baidu.com");
}

Java

Copy

完成修改。

3.接口测试

GET请求:http://127.0.0.1:30000/oauth/authorize?client_id=c1&response_type=code&scope=ROLE_API&redirect_uri=https://www.baidu.com 获取授权码后,观察表oauth_code,里面应当已经有了授权码数据。

四、源码地址

源码地址:https://gitee.com/kdyzm/spring-security-oauth-study/tree/v4.0.0

Spring Security OAuth2.0认证授权三:使用JWT令牌相关推荐

  1. Spring Security OAuth2.0认证授权五:用户信息扩展到jwt

    历史文章 [Spring Security OAuth2.0认证授权一:框架搭建和认证测试] [Spring Security OAuth2.0认证授权二:搭建资源服务] [Spring Securi ...

  2. Spring Security OAuth2.0认证授权知识概括

    Spring Security OAuth2.0认证授权知识概括 安全框架基本概念 基于Session的认证方式 Spring Security简介 SpringSecurity详解 分布式系统认证方 ...

  3. Spring Security OAuth2.0认证授权

    文章目录 1.基本概念 1.1.什么是认证 1.2 什么是会话 1.3什么是授权 1.4授权的数据模型 1.4 RBAC 1.4.1 基于角色的访问控制 2.基于Session的认证方式 3.整合案例 ...

  4. 基于Session的认证方式_实现授权功能_Spring Security OAuth2.0认证授权---springcloud工作笔记118

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 我们来实现基本的,session的授权功能,很简单实际上就是利用了springmvc的拦截器.不多 ...

  5. 基于Spring Security的认证方式_创建工程_Spring Security OAuth2.0认证授权---springcloud工作笔记119

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 首先加入依赖,除了以前的springmvc的依赖,还要security的依赖,这一次 然后这里配置 ...

  6. Spring Security OAuth2.0_实现分布式认证授权_集成测试_Spring Security OAuth2.0认证授权---springcloud工作笔记155

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 然后前面我们已经把分布式微服务的,认证授权全部集成了,然后我们来测试. 启动资源微服务order微 ...

  7. OAuth2.0_环境介绍_授权服务和资源服务_Spring Security OAuth2.0认证授权---springcloud工作笔记138

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 环境介绍 1.可以看到客户端首先访问/oauth/token 这个路径来请求令牌,这个接口是spr ...

  8. OAuth2.0_环境搭建_Spring Security OAuth2.0认证授权---springcloud工作笔记139

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 注意因为springsecurity,本身支持oauth2.0的协议.所以这里可以说springs ...

  9. OAuth2.0_介绍_Spring Security OAuth2.0认证授权---springcloud工作笔记137

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 上面是oauth2.0的一些介绍. 我们说一下oauth2.0的一个验证的过程, oauth2.0 ...

最新文章

  1. 主席树 ---- CF 1422F. Boring Queries(由离线推出在线如何求的 ,求解多次询问的区间LCM)
  2. jenkins环境搭建
  3. CSS实现段落首行缩进、1.5倍行距、左右对齐
  4. 通过QuartzCore/CoreAnimation.h实现让玫瑰花飞舞
  5. 浅谈jQuery的选择器
  6. spring的@ControllerAdvice注解
  7. linux etc/init 与etc/init.d的区别
  8. web版本 开源压测工具_Web压测工具之Webbench和http_load
  9. django判断ajax,Django ajax 检测用户名是否已
  10. 下十页分页php,织梦二次开发实现栏目分页前十页后十页功能
  11. Windows 10 如何添加开机启动项
  12. XILINX VIVADO2018.2官方下载全教程记录.
  13. 谈谈OSI模型和它的数据传输
  14. lisp实心圆点怎么画_实心小圆点符号怎么打
  15. Whisper的应用
  16. 【MM VS价】移动平均价V标准价格S(一)
  17. 用MSNCartoon制作个性化卡通头像
  18. 【数值分析×机器学习】以SVD的分解形式进行深度神经网络的训练(逐渐熟练)
  19. 计算机菜单在桌面未显示怎么找回,电脑桌面开始菜单不见和任务栏消失怎么办...
  20. android之SDK

热门文章

  1. 生鲜配送app功能概述以及优势分析
  2. Vue.js 定义组件模板的 7 种方式
  3. 【JavaWeb】jQuery WeUI框架 地址选择器 City-Picker 自定义demo
  4. 这才是成年人最崩溃的时刻
  5. 时间序列的自回归模型—从线性代数的角度来看
  6. [K8S] 环境变量获取
  7. 查询快递,查看单号更新几条物流信息
  8. 【进阶C语言】静态版通讯录的实现(详细讲解+全部源码)
  9. FLUKE DSX-8000andDTX-1800对比,究竟有何不同?
  10. CSDN产品周报第23期|叮~2021 CSDN年度报告已出炉;私信新增拉黑功能;创作助手支持错别字检测……