1. 程式人生 > >spring boot spring security 自定義 filter FilterSecurityInterceptor 訪問資源 靜態資源 和 不需要許可權訪問都失效了

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