spring boot spring security 自定義 filter FilterSecurityInterceptor 訪問資源 靜態資源 和 不需要許可權訪問都失效了
問題: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