SpringOAuth2再深入

标签: Springboot 分类: Java 创建时间:2020-08-13 01:39:30 更新时间:2023-10-20 11:23:26

1.Lambda表达式

看了很多的Spring Security和OAuth2的文章,还是感觉有很多的东西都不懂,也不会,虽然通过(微服务权限终极解决方案,Spring Cloud Gateway + Oauth2 实现统一认证和鉴权! 这篇文章,运行起来了一个简单的OAuth2服务器认证以及网关,但是等自己再深入的修改代码的时候,发现自己还是改不动。

一个简单的例子就是,下面这句话,这里其实设及到了很多的东西,奈何我作为一个开发Java说时间长也长,说时间端也短的杂牌,愣是没看懂。

1
roleCodes.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());

这句话其实是在UserDetails中,获取用户角色里面的内容,里面涉及到的知识点,一个就是stream()。

1
2
3
4
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roleCodes.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
}

SimpleGrantedAuthority::new可以替换为:

1
roleStr->new SimpleGrantedAuthority(roleStr)

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串。collect(Collectors.toList())的操作,我觉得其实就是将流中的内容操作完成之后,又转化为了List集合。

参考文章:
1.SpringCloud Alibaba微服务实战十四 - SpringCloud Gateway集成Oauth2.0
2.Java 8 Stream (Java中的Stream讲解)
3.Spring Boot + Security + JWT 实现Token验证+多Provider——登录系统 (学习的思路还是很不错的,记得跟踪代码,从代码的流程中学习整个认证的流程,还有就是代码的注释,其中的注释,也有助于理解相关的问题)
4.SpringSecurity动态加载用户角色权限实现登录及鉴权 (这里简单的分析了如何从数据库动态获取用户的角色和权限信息)
5.详解Spring Security的formLogin登录认证模式 (这里有一点我觉得对我帮助很大,就是说:authorities(“biz1”,”biz2”)指的是user用户拥有资源ID为biz1(业务一)和biz2(业务二)资源的权限,这里的资源ID我觉得其实可以理解为用户角色的概念)
6.Java 8 Stream (这个关于Stream的说明,我觉得可以好好看看)
7.Java8中的[方法引用]“双冒号”——走进Java Lambda(四) (这是双冒号的用法)

2.服务注册的时间

今天在部署应用程序的时候,突然想到了,给的事例中,哪里完成了服务注册呢?

参考文章:
1.Spring Cloud OAuth2 实现用户认证及单点登录 (这篇文章其实和我的参考文章非常的像,流程大体上都是这么个流程,这里作为补充说明)
2.Nacos 服务注册 (服务注册和源代码解析,还有和其他的注册中心进行比较的优缺点)

3.accessDeniedHandler和authenticationEntryPoint不起作用

我在代码中配置了accessDeniedHandler和authenticationEntryPoint处理器,但是如果access_token过期了或者是不正确,都不会进入到相应的处理方法中。

1
2
3
4
5
6
7
http.authorizeExchange()
.pathMatchers(ArrayUtil.toArray(ignoreUrlsConfig.getUrls(),String.class)).permitAll()//白名单配置
.anyExchange().access(authorizationManager)//鉴权管理器配置
.and().exceptionHandling()
.accessDeniedHandler(restfulAccessDeniedHandler)//处理未授权
.authenticationEntryPoint(restAuthenticationEntryPoint)//处理未认证
.and().csrf().disable();
参考文章:
1.Spring Boot:accessDeniedHandler不起作用
2.spring security中配置了AccessDeniedHandler没有生效问题 (这里就是说使用hasRole,进行异常的捕获,但是问题还是没有解决)

这个问题,还有一个突破点就是如何自定义jwt验证过程。

随着一步步的深入,我找到了http.oauth2ResourceServer().jwt()可以配置一个jwtDecoder,但是在很多的参考文章中,jwtDecoder又涉及到一个OAuth2ResourceServerProperties 属性的东西。

最后的解决方案就是定义oauth2ResourceServer().authenticationEntryPoint()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter());

//自定义处理JWT请求头过期或签名错误的结果(新添加的)
http.oauth2ResourceServer().authenticationEntryPoint(restAuthenticationEntryPoint);

http.authorizeExchange()
.pathMatchers(ArrayUtil.toArray(ignoreUrlsConfig.getUrls(),String.class)).permitAll()//白名单配置
.anyExchange().access(authorizationManager)//鉴权管理器配置
.and().exceptionHandling()
.accessDeniedHandler(restfulAccessDeniedHandler)//处理未授权
.authenticationEntryPoint(restAuthenticationEntryPoint)//处理未认证
.and().csrf().disable();
return http.build();
}
参考文章:
1.Using JWT with Spring Security OAuth (我按这篇文章进行了JwtDecoder的定义,但是似乎没有起作用)
2.Allow configuring oauth2ResourceServer() with custom provider (这篇文章中,我有了新的突破点,就是http.oauth2ResourceServer().jwt().authenticationManager(new MyCustomAuthenticationManager())。既然可以添加authenticationManager,是不是还可以添加其他的方法和验证逻辑呢?)
3.Test JwtDecoder in @WebMvcTest with Spring Security
4.我扒了半天源码,终于找到了Oauth2自定义处理结果的最佳方案! (这篇文章最后解决了我的问题,通过oauth2ResourceServer().authenticationEntryPoint()定义鉴权失败的返回结果,这篇文章应该是我创建OAuth2的参考代码是同一个作者,还包括了白名单处理,全局认证错误处理等内容)
5.如何在Spring Boot OAuth2中自定义JWT解码器 (这篇文章还没有看的很懂,虽然作者说解决了问题,但是我是没有看明白)
6.Spring Boot 2.x实战84 – Spring Security 8 -OAuth 2.0之Resource Server(基于JWT) (这篇文章有些内容还是不错的,主要就是说Spring Boot的自动配置,以及OAuth2ResourceServerJwtConfiguration:配置JWT Token解码的JwtDecoder。但是最后我想知道的就是如何配置JwtDecoder解码器,没有介绍)
7.serSpring Security 中文文档 (这是教程性的一系列文档,可以进行深入的学习,但是不利于针对性的查找想关问题,但是我搜了JwtDecoder,文章中也是有部分解释的)

4.OAuth2放行部分URL不生效

在使用OAuth2进行权限认证的时候,添加了上面的authenticationEntryPoint(restAuthenticationEntryPoint),自定义请求头过期的方法,但是随之出现的一个问题就是:只要我的http请求头中包含了Authorization请求头,那么就会进入jwt认证,如果这个Authorization请求头的内容不合理或者过期了,就会进入出错流程,无论我这个http是不是需要进行认证,比如auth/oauth/token请求,无论是携不携带Authorization,本来都是不需要认证的。

在参考文章中,有这么一句话,就是在OAuth2 Resource Server启动时,会处理包含Authorization:Bearer标头的任何请求,我现在要作的就是禁止处理部分请求。

最后还是在 ( 我扒了半天源码,终于找到了Oauth2自定义处理结果的最佳方案! )中找到了解决方案(所有的源代码基本都是他的)

其实我们只要在Oauth2默认的认证过滤器前面再加个过滤器,如果是白名单接口,直接移除认证头即可,首先定义好我们的过滤器;

通过添加这么一个Filter,在遇到百名单的时候,直接移除掉相关的配置就好了,什么问题都解决了。

参考文章:
1.Implementing JWT Authentication on Spring Boot APIs (没什么用)
2.Reactive Authorization in Spring Security (主要的还是说在http中配置ReactiveAuthorizationManager)
3.Interface ReactiveAuthorizationManager (关于ReactiveAuthorizationManager的类说明,其中还有一点让我疑惑的就是Mono这个东西)
4.9.Spring Security 5.1之 OAuth 2.0 Resource Server (这明显是一个翻译的文章,很多东西都有点不通顺。但是也有可取的地方,第一个就是:在服务启动时Resource Server将尝试处理包含Authorization:Bearer标头的任何请求,还有就是指定JwtDecoder实例,配置验证方法等都很有用)
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。