springsecurity授权源码梳理
时序图借用
登陆认证过程中涉及的filter过滤器整理
从图中可以看出执行的顺序。来看看个人认为比较重要的 几个Filter 的处理逻辑,
1.UsernamePasswordAuthenticationFilter
上一篇中登陆认证的过程中使用。
2.AnonymousAuthenticationFilter
//org.springframework.security.web.authentication.AnonymousAuthenticationFilter
//创建一个用户名为anonymousUser授权为ROLE_ANONYMOUS
public AnonymousAuthenticationFilter(String key) {
this(key, "anonymousUser", AuthorityUtils.createAuthorityList(new String[]{"ROLE_ANONYMOUS"}));
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
//如果前面的过滤器都没认证通过
if (SecurityContextHolder.getContext().getAuthentication() == null) {
//为当前的SecurityContextHolder中添加一个匿名的AnonymousAuthenticationToken
SecurityContextHolder.getContext().setAuthentication(this.createAuthentication((HttpServletRequest)req));
}
chain.doFilter(req, res);
}
//创建匿名的AnonymousAuthenticationToken
protected Authentication createAuthentication(HttpServletRequest request) {
AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(this.key, this.principal, this.authorities);
auth.setDetails(this.authenticationDetailsSource.buildDetails(request));
return auth;
}
3.ExceptionTranslationFilter
ExceptionTranslationFilter是异常处理过滤器,处理在系统认证授权过程中抛出的异常,主要处理AuthenticationException和AccessDeniedException异常
//org.springframework.security.web.access.ExceptionTranslationFilter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
try {
chain.doFilter(request, response);
} catch (IOException var9) {
throw var9;
} catch (Exception var10) {
//判断是否为AuthenticationException异常
Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(var10);
RuntimeException ase = (AuthenticationException)this.throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
if (ase == null) {
//判断是否为AccessDeniedException异常
ase = (AccessDeniedException)this.throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
}
if (ase == null) {
//如果上面异常没有匹配到 则判断是否为ServletException异常
if (var10 instanceof ServletException) {
throw (ServletException)var10;
}
//如果上面异常没有匹配到 则判断是否为RuntimeException异常
if (var10 instanceof RuntimeException) {
throw (RuntimeException)var10;
}
throw new RuntimeException(var10);
}
if (response.isCommitted()) {
throw new ServletException("Unable to handle the Spring Security Exception because the response is already committed.", var10);
}
this.handleSpringSecurityException(request, response, chain, (RuntimeException)ase);
}
}
4.FilterSecurityInterceptor
此过滤器是认证授权过程中最后一个过滤器,该过滤器之后才是具体的映射请求 如/menu/menus
//org.springframework.security.web.access.intercept.FilterSecurityInterceptor
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
public void init(FilterConfig arg0) throws ServletException {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
this.invoke(fi);
}
public void invoke(FilterInvocation fi) throws IOException, ServletException {
if (fi.getRequest() != null && fi.getRequest().getAttribute("__spring_security_filterSecurityInterceptor_filterApplied") != null && this.observeOncePerRequest) {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} else {
if (fi.getRequest() != null && this.observeOncePerRequest) {
fi.getRequest().setAttribute("__spring_security_filterSecurityInterceptor_filterApplied", Boolean.TRUE);
}
//****重要****
//执行父类org.springframework.security.access.intercept.AbstractSecurityInterceptor的beforeInvocation()方法
//下面讲解
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
//可以理解为 **** 才是具体的映射请求 如/menu/menus ****
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.finallyInvocation(token);
}
super.afterInvocation(token, (Object)null);
}
}
}
5.AbstractSecurityInterceptor
FilterSecurityInterceptor 的父类
//org.springframework.security.access.intercept.AbstractSecurityInterceptor
protected InterceptorStatusToken beforeInvocation(Object object) {
if (!this.getSecureObjectClass().isAssignableFrom(object.getClass())) {
throw new IllegalArgumentException();
} else {
//注:获取自定义匹配规则
//this.obtainSecurityMetadataSource()为当前类定义的抽象方法
//DefaultFilterInvocationSecurityMetadataSource为SecurityMetadataSource的子类
//默认调用DefaultFilterInvocationSecurityMetadataSource中的getAttributes()方法
Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
if (attributes != null && !attributes.isEmpty()) {
if (SecurityContextHolder.getContext().getAuthentication() == null) {
this.credentialsNotFound(this.messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound", "An Authentication object was not found in the SecurityContext"), object, attributes);
}
Authentication authenticated = this.authenticateIfRequired();
try {
//*****重点*****
//authenticated 当前认证过的Authentication
//object ??????
//attributes ?????
this.accessDecisionManager.decide(authenticated, object, attributes);
} catch (AccessDeniedException var7) {
this.publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated, var7));
throw var7;
}
if (this.publishAuthorizationSuccess) {
this.publishEvent(new AuthorizedEvent(object, attributes, authenticated));
}
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attributes);
if (runAs == null) {
return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attributes, object);
} else {
SecurityContext origCtx = SecurityContextHolder.getContext();
SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
SecurityContextHolder.getContext().setAuthentication(runAs);
return new InterceptorStatusToken(origCtx, true, attributes, object);
}
} else if (this.rejectPublicInvocations) {
throw new IllegalArgumentException();
} else {
this.publishEvent(new PublicInvocationEvent(object));
return null;
}
}
}
//为获取attributes使用
public abstract SecurityMetadataSource obtainSecurityMetadataSource();
调试中观察到
1)object为当前请求的url 如/menu/menus
2)attributes
默认会调用org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource类中的getAttributes()方法
public Collection<ConfigAttribute> getAttributes(Object object) {
HttpServletRequest request = ((FilterInvocation)object).getRequest();
Iterator var3 = this.requestMap.entrySet().iterator();
Entry entry;
do {
if (!var3.hasNext()) {
return null;
}
entry = (Entry)var3.next();
} while(!((RequestMatcher)entry.getKey()).matches(request));
return (Collection)entry.getValue();
}
6.AccessDecisionManager授权
AccessDecisionManager是接口
Spring Security默认使用AffirmativeBased实现AccessDecisionManager 的 decide 方法来实现授权。
//org.springframework.security.access.vote.AffirmativeBased
public class AffirmativeBased extends AbstractAccessDecisionManager {
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {
int deny = 0;
Iterator var5 = this.getDecisionVoters().iterator();
while(var5.hasNext()) {
//1.调用AccessDecisionVoter的vote()方法进行投票
AccessDecisionVoter voter = (AccessDecisionVoter)var5.next();
int result = voter.vote(authentication, object, configAttributes);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Voter: " + voter + ", returned: " + result);
}
switch(result) {
case -1://投票为-1 则记录一下
++deny;
break;
case 1://投票为1 直接返回
return;
}
}
if (deny > 0) {
//如果有两个及以上AccessDecisionVoter(姑且称之为投票者吧)都投-1,则直接就不通过了
//抛出AccessDeniedException 未授权
throw new AccessDeniedException();
} else {
this.checkAllowIfAllAbstainDecisions();
}
}
}