文章目录
4 鉴权
从Spring Security的过滤器链中,我们已经发现位于最后的FilterSecurityInterceptor是用来进行权限认证的,这一节将详细分析Spring Security是如何进行权限认证的。
4.1 FilterSecurityInterceptor
源码分析:
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements
Filter {
private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied";
...
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
...
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 {
//第一次调用此请求时,请执行安全检查
if (fi.getRequest() != null && observeOncePerRequest) {
fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
}
//before
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
//过滤器链
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}
finally {
//finally
super.finallyInvocation(token);
}
//after
super.afterInvocation(token, null);
}
}
}
这段代码的主要逻辑就是调用了父类的beforeInvocation
、开启filter链式调用、finallyInvocation
和afterInvocation
方法。filter的链式调用就是获取配置好的filter,按照顺序依次进行调用,接下来重点看一下父类做了什么。
AbstractSecurityInterceptor
AbstractSecurityInterceptor是一个实现了对受保护对象的访问进行拦截的抽象类,先来看一下它的源码:
public abstract class AbstractSecurityInterceptor implements InitializingBean,
ApplicationEventPublisherAware, MessageSourceAware {
...
//对返回值进行修改
private AfterInvocationManager afterInvocationManager;
//改变鉴权过后的Authentication
private RunAsManager runAsManager = new NullRunAsManager();
...
protected InterceptorStatusToken beforeInvocation(Object object) {
...
//获取配置的权限信息
Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
.getAttributes(object);
...
//身份认证是否完成
Authentication authenticated = authenticateIfRequired();
try {
//资源权限认证
this.accessDecisionManager.decide(authenticated, object, attributes);
}
...
// Attempt to run as a different user
//修改保存在SecurityContext中的Authentication
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object,
attributes);
...
}
//请求完毕后进行清理
protected void finallyInvocation(InterceptorStatusToken token) {
if (token != null && token.isContextHolderRefreshRequired()) {
...
SecurityContextHolder.setContext(token.getSecurityContext());
}
}
protected Object afterInvocation(InterceptorStatusToken token, Object returnedObject) {
finallyInvocation(token); // continue to clean in this method for passivity
if (afterInvocationManager != null) {
// Attempt after invocation handling
try {
//重点
returnedObject = afterInvocationManager.decide(token.getSecurityContext()
.getAuthentication(), token.getSecureObject(), token
.getAttributes(), returnedObject);
}
...
}
return returnedObject;
}
private Authentication authenticateIfRequired() {
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
//判断身份认证是否完成
if (authentication.isAuthenticated() && !alwaysReauthenticate) {
return