Spring Security 如何进行权限验证

阅读本文之前,请投票支持这款 全新设计的脚手架 ,让 Java 再次伟大!

FilterSecurityInterceptor

FilterSecurityInterceptor 是负责权限验证的过滤器。一般来说,权限验证是一系列业务逻辑处理完成以后,最后需要解决的问题。所以默认情况下 security 会把和权限有关的过滤器,放在 VirtualFilter chains 的最后一位。

FilterSecurityInterceptor.doFilter 方法定义了两个权限验证逻辑。分别是 super.beforeInvocation 方法代表的权限前置验证与 super.afterInvocation 代表的后置权限验证。

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);
		}

		InterceptorStatusToken token = super.beforeInvocation(fi);

		try {
   
   
			fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
		}
		finally {
   
   
			super.finallyInvocation(token);
		}

		super.afterInvocation(token, null);
	}
}

和身份验证的设计类似,前置权限验证的业务处理也是参考模板方法设计模式的理念,将核心处理流程定义在父类(super) AbstractSecurityInterceptor 中的。

InterceptorStatusToken token = super.beforeInvocation(fi);

再通过关联 AccessDecisionManager 的方式,把身份验证通过的认证对象委托给 AccessDecisionManager 执行。

Authentication authenticated = authenticateIfRequired();
Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
.getAttributes(object);
		// Attempt authorization
try {
   
   
	this.accessDecisionManager.decide(authenticated, object, attributes);
}
catch (AccessDeniedException accessDeniedException) {
   
   
	publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,
		accessDeniedException));

	throw accessDeniedException;
}

		// Attempt to run as a different user
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object,
	attributes);

if (runAs == null) {
   
   
	if (debug) {
   
   
		logger.debug("RunAsManager did not change Authentication object");
	}

			// no further work post-invocation
	return new InterceptorStatusToken(SecurityContextHolder.getContext(), false,
		attributes, object);
}
else {
   
   
	if (debug) {
   
   
		logger.debug("Switching to RunAs Authentication: " + runAs);
	}

	SecurityContext origCtx = SecurityContextHolder.getContext();
	SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
	SecurityContextHolder.getContext().setAuthentication(runAs);

			// need to revert to token.Authenticated post-invocation
	return new InterceptorStatusToken(origCtx, true, attributes, object);
}

在前置权限校验执行完毕后,会使用 this.runAsManager.buildRunAs 与 SecurityContextHolder.getContext().setAuthentication(runAs) 方法将当前上下文中的身份认证成功的对象备份,然后重新拷贝一个新的鉴权成功的对象到上下文的中。


		// Attempt to run as a different user
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object,
	attributes);

	SecurityContext origCtx = SecurityContextHolder.getContext();
	SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
	SecurityContextHolder.getContext(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值