Spring Security默认过滤器链之FilterSecurityInterceptor(十四)

1.作用

这个主要是针对http请求进行权限校验

权限校验需要注意的几点:

1.用户需要先认证

2.获取资源所需授权

3.获取用户被授权信息

4.授权校验

5.授权成功处理

6.授权失败处理



2.直接开撸

2.1 参数封装
public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// 先构建了一个封装类,将request,response,chain放入。
		// 这种设计的目的一般是因为这三个参数需要多处传递
		// 其二就是FilterInvocation 会对着三个参数的数据获取进行包装和修饰(就是封装成你想要的)
		FilterInvocation fi = new FilterInvocation(request, response, chain);
		invoke(fi);
	}

2.2 核心代码
public void invoke(FilterInvocation fi) throws IOException, ServletException {
		if ((fi.getRequest() != null)
				&& (fi.getRequest().getAttribute(FILTER_APPLIED) != null)
				&& observeOncePerRequest) {
			// filter already applied to this request and user wants us to observe
			// once-per-request handling, so don't re-do security checking
			// 上面的这个判断就是判断这个过滤器是否被重复执行的
			// 如果重复执行了,就跳过下面的内容,直接执行拦截器链的下一条
			fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
		}
		else {
			// first time this request being called, so perform security checking
			if (fi.getRequest() != null && observeOncePerRequest) {
				// 设置已被执行的标识
				fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
			}
			// 核心方法1:通过FilterInvocation来获取用户的SecurityContext,
			// 授权信息(ConfigAttribute),授权对象(secureObject)等封装类
			InterceptorStatusToken token = super.beforeInvocation(fi);

			try {
				fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
			}
			finally {
				// 核心方法2:基于用户授权信息封装类判断用户是否能通过授权
				super.finallyInvocation(token);
			}
			// 核心方法3:
			super.afterInvocation(token, null);
		}
	}


3.先看看核心方法1 beforeInvocation

1.检查当前被授权对象跟过滤器是否匹配

当前一共有两种过滤器来进行授权,一种是FilterSecurityInterceptor,一种是MethodSecurityInterceptor

然后这两种都提供了各自的封装

FilterInvocation : 主要是针对url 授权

MethodInvocation: 主要是针对方法 授权

这里就是检查传入的Invocation和当前过滤器能处理的Invocation是否一致。
在这里插入图片描述


2.获取权限ConfigAttribute

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6LOqKlst-1626337393229)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a52b431d-6c70-4801-9f6e-1a1e2f28aa7d/Untitled.png)]
当没有获取配置的权限信息时,那就是说,不需要鉴权了。

那如何通过FilterInvocation去获取权限信息的呢?在DefaultFilterInvocationSecurityMetadataSource中通过RequestMatcher去匹配url来获取对应的权限。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ztv341n-1626337393230)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e2ae1bf0-8fbd-4998-9bf6-db4f6857f175/Untitled.png)]

那DefaultFilterInvocationSecurityMetadataSource的信息都是写什么呢?我通过debug发现,在FilterSecurityInterceptor中使用的FilterInvocationSecurityMetadataSource的实现类是DefaultFilterInvocationSecurityMetadataSource的子类FilterInvocationSecurityMetadataSource。

下面看看FilterInvocationSecurityMetadataSource的具体内容。


3.FilterInvocationSecurityMetadataSource 基于url的权限元数据信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nmmH2EVq-1626337393232)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/4d624da4-1651-43ed-bf76-41a0700d970c/Untitled.png)]

通过debug发现ExpressionBasedFilterinvocationSecurityMetadataSource 是默认的FilterInvocationSecurityMetadataSource的默认实现。

fullAuthenticated() : 需要完全授权,也就是rememberMe的这种不能访问

denyAll(): url匹配的都不允许访问

这种就是你针对spring security的全局权限配置信息。

4.检查认证信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NLIJFYQs-1626337393236)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/4540fd21-ea48-4ce3-a99f-918997580901/Untitled.png)]

5.授权校验

AccessDecisionManager 这个权限校验体系很有意思。

针对一个资源(图片,js等静态资源,http请求)Spring Security设定了多种多种权限控制。

所以在设计AccessDecisionManager时,它只是用于对授权的汇总和最终决策。

至于具体的鉴权是由AccessDecisionVoter实现类来完成的。

AccessDecisionVoter有三种返回结果:授权,弃权,拒绝

每个AccessDecisionManager有一个AccessDecisionVoter的集合,针对这个集合对权限的校验结果,

AccessDecisionManager 默认有三种决策方案。

AccessDecisionManager有三个实现子类

AffirmativeBased: 有授权通过的就直接授权通过

ConsensusBased: 授权数大于拒绝数,则授权通过。至于授权数等于拒绝数,则根据配置决定。

UnanimousBased:有拒绝就直接拒绝


好了,回到正题。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ypy2Pr8h-1626337393238)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0c2b3264-e3d5-4014-8479-172b240e59e2/Untitled.png)]

FilterSecurityInterceptor的默认授权投票管理器(AccessDecisionManger)方案是AffirmativeBased,这也就是意味着,有一个授权通过就算通过了。授权失败直接抛AccessDeniedException异常,然后交给ExceptionTranslationFilter处理就行了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrjKj9Ul-1626337393240)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2a8ca046-b941-43bf-b07f-665fc35b865a/Untitled.png)]

6.RunAsManager 角色扮演

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w3h1wCep-1626337393241)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/43c4b077-278d-480e-9bca-f151d6c9aa44/Untitled.png)]

上面是在干啥呢?

1.RunAsManager去构建认证信息Authentication

当然FIlterSecurityInterceptor默认的RunAsManager实现类是NullRunAsManager。这个类什么也不做。

但是如果要用的话,它有个实现类RunAsManagerImpl,这个类就是将现有的权限ConfigAttribute类中有以RUN_AS_开头的权限。则在前面添加ROLE_ 来作为一个角色权限。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-20y2r9IA-1626337393243)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/89f0b0b8-0c37-4902-845f-9d84ed39474c/Untitled.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mYRIKkK1-1626337393244)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/24b4902f-5e98-4502-8c5d-3da65f2524fd/Untitled.png)]

2.当RunAsManager的鉴权信息为null时

说明没有需要扮演的角色。直接返回授权信息InterceptorStatusToken

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3ojSuqT-1626337393244)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9f52a89b-307f-431c-ba11-b749a9b1b284/Untitled.png)]


3.当RunAsManager的鉴权信息不为null时

这个时候针对这个请求,由于权限得以临时提升,那么需要临时构建SecurityContext来存储临时认证授权信息。 当然原来的SecurityContext不能动,毕竟这个权限提升只是针对当前请求的。所以原始的SecurityContext要保存起来,后面再重置回来。毕竟SecurityContext是每个请求都要使用的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGHzPY1C-1626337393246)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e43f319d-2e62-49d7-9bd1-20b0ce5286ed/Untitled.png)]


7.beforeInvocation小结

这个就是用来进行url权限授权的,然后也可以针对指定请求进行权限提升。设计还是比较巧妙的。

其中AccessDecisionManager 授权决策管理器, AccessDecisionVoter 针对权限的检验器 两者的联合创造了更多权限校验方式。

可以瞅瞅权限校验器的子类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QioJiknK-1626337393247)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f1fcf101-bcc1-452b-9801-91846b30ccc5/Untitled.png)]



4. 核心方法2 finallyInvocation

这个其实就是为了将RunAsManager修改的SecurityContextHolder进行重置。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1YTCsCcw-1626337393248)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c353c197-f0ef-459f-aa94-81bf3021fc3c/Untitled.png)]

5. 核心方法3 afterInvocation

这个是干啥呢?就是在过滤器链执行完请求回来时,诶,我如果想对返回结果来一顿操作时,那么可以通过AfterInvocationManager来进行操作。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4B4qDkMN-1626337393249)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/94cc668a-c250-4f18-8cfe-f72832d2cfba/Untitled.png)]

AfterInvocationManager就跟AccessDecisionManager很相似。

AfterInvocationManager持有List<AfterInvocationProvider>,通过AfterInvocationProvider来进行修改返回结果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S6nhmTBg-1626337393252)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/bd62c322-e62d-4c2a-9df4-dd457bf5bcb4/Untitled.png)]



6.小结

这个过滤器中,我了解了基于url匹配授权的基本过程。其中的三个重要组件,AccessDecisionManager,RunAsManager,AfterInvocationManager是值得深挖的。其中的设计思想和思路值得学习。

由于工作中暂时未使用到,且自身的学习计划比较紧张。所以这里针对许多可以扩展的地方并没有去扩展,由此产生的不好的阅读体验深感抱歉。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欢谷悠扬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值