问题:spring boot security 中, filters="none" 对应哪个?
自定义AbstractSecurityInterceptor后 静态资源也进入拦截器,登陆页面,permitall 也失效,
还是进入了filter
参考:http://blog.51cto.com/winters1224/2052034
调试源代码发现,采用默认的 FilterSecurityInterceptor 过滤器 时,使用默认的DefaultFilterInvocationSecurityMetadataSource
里面的requestmap加载了对应的antMatchers("xxxx","xxx").permitAll() 里面的url 作为key,并且value 里面设置为permitAll
,后面默认的决策器就是因为这个permitAll,所以容许访问。
(FilterSecurityInterceptor 里的
AbstractSecurityInterceptor 里的beforeInvocation 会调用 DefaultFilterInvocationSecurityMetadataSource 的getAttributes
然后 里面会访问
private final Map<RequestMatcher, Collection<ConfigAttribute>> requestMap;
刚好是permitall。所以ok.
antMatchers permitall 这种是 对应这个ExpressionUrlAuthorizationConfigurer,而这个是对应的过滤器 FilterSecurityInterceptor,所以自己定义的里面没有?是这个原因么?
如果自定义FilterSecurityInterceptor 确实是走的自己的decide方法,那肯定默认的FilterSecurityInterceptor就没走了。默认的decide方法 AffirmativeBased 类中的decide方法
于是想了一下,自定义FilterSecurityInterceptor 如果放到 默认的FilterSecurityInterceptor 后面,如下
http.addFilterAfter(customFilterSecurityInterceptor, FilterSecurityInterceptor.class)
先走的 默认的FilterSecurityInterceptor ,那么应该就可以了。结果发现,是默认的FilterSecurityInterceptor 是通过了,但是还是会接着往下走剩余的过滤器(自定义的FilterSecurityInterceptor),又卡住了。
于是想着要么重写他的decide吧。复制过来。可是一看太麻烦了。算了。如下:
public void decide(Authentication authentication, Object object,
Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {
int deny = 0;
for (AccessDecisionVoter voter : getDecisionVoters()) {
int result = voter.vote(authentication, object, configAttributes);
if (logger.isDebugEnabled()) {
logger.debug("Voter: " + voter + ", returned: " + result);
}
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
return;
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
break;
}
}
if (deny > 0) {
throw new AccessDeniedException(messages.getMessage(
"AbstractAccessDecisionManager.accessDenied", "Access is denied"));
}
// To get this far, every AccessDecisionVoter abstained
checkAllowIfAllAbstainDecisions();
}
具体再细一点的细节,跟的脑袋晕,不跟了,先到这里。
)
参考:http://www.tianshouzhi.com/api/tutorials/spring_security_4/264
public class DefaultFilterInvocationSecurityMetadataSource implements
FilterInvocationSecurityMetadataSource {
protected final Log logger = LogFactory.getLog(getClass());
private final Map<RequestMatcher, Collection<ConfigAttribute>> requestMap;
.......................................
public Collection<ConfigAttribute> getAttributes(Object object) {
final HttpServletRequest request = ((FilterInvocation) object).getRequest();
for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap
.entrySet()) {
if (entry.getKey().matches(request)) {
return entry.getValue();
}
}
return null;
}
另外要说的就是permitall 还是要走所有的过滤器,直到最后一个过滤器FilterSecurityInterceptor 认定是可以放过的,才能访问。
所以如果有些不需要设置权限的,就放到web.ignoring() 中。因为总的是两个大的过滤器,一个是忽略的过滤器,一个是11个过滤器链。
@Override
public void configure(WebSecurity web) throws Exception {
//解决静态资源被拦截的问题
web.ignoring().antMatchers("/res/**");
}
如图,
断点是org.springframework.security.web的 FilterChainProxy类,从chain中看得到,4是springsecurity的过滤链。其他是系统的。
然后springsecurity 里面有两个大的,第一个就是对应不拦截的,filters是0,表示匹配"/res/**" 路径的不用任何拦截器。
第二个,就是大的过滤链,一共12个,里面有我自己定义的一个。原始的是11个。
结论就是就放到web.ignoring() 中 不进入这些过滤器就是最好最高效的。
其他参考:http://www.blogjava.net/SpartaYew/archive/2011/06/15/350630.html