Spring Security 授权问题

最近在学Spring Security,有些不懂的问题想请教各位大佬

开始当然是官方默认配置跑起来,还没有什么问题
后来自定义认证授权这里,我继承实现了UsernamePasswordAuthenticationFilter、AuthenticationProvider。
在UsernamePasswordAuthenticationFilter里网上都是setAuthenticationSuccessHandler来执行认证成功后的操作,是在里面直接写response就结束了,但我理解正常的场景应该是通过账号密码或者是token认证成功后继续向下执行该接口的具体业务。所以我没有指定setAuthenticationSuccessHandler,想让他继续执行下去,当他走到匿名过滤器AnonymousAuthenticationFilter的时候,第90行SecurityContextHolder.getContext().getAuthentication()为空,此时认证信息就没了然后生成一个匿名认证,在下一层FilterSecurityInterceptor就被403拦下来了

login 设的 permitAll
其余都是anyRequest().authenticated()
不知道该怎么操作才能调到具体接口执行下面,还望各位大佬指点一下

代码地址
https://github.com/ChiMuYuan/demo/tree/main/security

  • 首先呢,security的provider内置的为DaoAuthenticationProvider,你既然重写provider你可以看下人家内置的逻辑,在这里面你可以重写认证的或者加密方式;
  • 其次就是登录成功或者失败的自定义的handler,hadnler类型很多,但是大的来说就三种:登录成功、登录失败、未鉴权的;你要重写就去实现顶层重写方法即可,AuthenticationSuccessHandlerAuthenticationFailureHandlerAccessDeniedHandler;
  • 再就是你文中提到的 重写了UsernamePasswordAuthenticationFilter,你仔细看看,security的核心就是过滤器,也就是不管你重写不重写我上面两条提到的东西,但是这个里面内容你既然重写了,那就必须按照规范重写实现逻辑,尤其是认证后的操作,然后去替换原有的filter,http.addFilterAt;这样你的过滤器才能生效;
  • 最后就是AnonymousAuthenticationFilter 进入这个过滤器那就意味着本身鉴权未通过,身份信息不存在所以才有匿名,自然而然SecurityContextHolder.getContext().getAuthentication()

一般来说重写 UsernamePasswordAuthenticationFilter是为了解决请求路径方式(默认登录url)和参数类型(form表单改json),多认证APP(多端认证)的时候才有,如果你没这些需求可以不重写;相反你可以重写一些登录或者认证的前面提到到handler实现响应的内容;

这里有个小例子,关于重写 hanler的

先谢谢老哥指点了。

我看了DaoAuthenticationProvider里面一些逻辑,最终调用的就是createSuccessAuthentication,返回的就是一个UsernamePasswordAuthenticationToken,我因为只是验证学习框架,没有写任何逻辑直接就返回了一个带GrantedAuthority集合的UsernamePasswordAuthenticationToken。
然后也进入了我自己写的success的handler,successHandler里面authentication入参的authenticated=true,但他还是继续往下走了,就到了 AnonymousAuthenticationFilter没了认证信息

我用了addFilterAt替换了原来的过滤器

我理解的是进入了我自己写的AuthenticationSuccessHandler就认为成功了,但是按老哥的说法只要后续进入了 AnonymousAuthenticationFilter,不管前面走没走successHandler就认为授权没通过。所以现在问题就是怎样才算真正授权通过了,我重写successHandler,直接用SavedRequestAwareAuthenticationSuccessHandler都试了

我这里是form改json

实在是没有搞懂,还请老哥指教,因为只是自己学的,里面代码很乱,后续我看整理下贴代码

这里面重写hanler也只是直接写getWriter返回了吧,能继续走下去访问到具体url的业务接口吗

我发现问题了,是因为SessionCreationPolicy.STATELESS,使用token这里就不创建session比较好,但这样认证就会变成不通过,只要不加STATELESS就可以了

最终问题:
SecurityContextPersistenceFilter在初始化的时候会使用默认的sessionContext,因为禁用了session,所以在AnonymousAuthenticationFilter之前执行的SecurityContextPersistenceFilter所初始化的repo(SecurityContextRepository)为NullSecurityContextRepository,从名字可知这是spring为防止null error 所构建的空repository,没有实际逻辑。所以在AnonymousAuthenticationFilter时,登录信息都被repo读取出来的null认证信息覆盖了,所以认证信息丢失,然后在AnonymousAuthenticationFilter里面被赋予了匿名权限。

所以解决方案有两种:

  1. 自己写一个SecurityContextPersistenceFilter(本人未验证,不知其中是否还有什么坑)
  2. 在AnonymousAuthenticationFilter的位置加入一个过滤器,使用SecurityContextHolder.getContext().setAuthentication(xxxxx)将认证成功或识别信息放入,这个过滤器里就可以写token的自定义逻辑(本方法已上传github,连接在1楼)
1 Like