運行基於form表單的acegitest2demo,你是否發現有什麼不妥?
測試不妥處如下:
2.肯定會轉到login頁面,然後登陸進去test/1,進入accessdefined無權限頁面。使用lisi/1,進入當前用戶信息。
但是:
哈哈,進入accessdefined無權限頁面。
我再打開IE瀏覽器,再運行這個url,還是進入無權限頁面。
是緩存?那我明明是新打開的瀏覽器啊,而不是打開新標籤啊?
無論你打開幾層IE瀏覽器,你F12看看,會發現,咦,sessionId是相同的。
這說明什麼問題?說明你用的IE瀏覽器是session共享的,這是瀏覽器爲用戶方便而專門爲用戶設置的。IE8默認情況下,session是共享的。
那如何新建一個session不同的頁面呢?
在IE中,文件—新建session會話即可。
修改瀏覽器的快捷方式屬性,在 C:\Program Files\Internet Explorer 文件夾下,通過iexplore.exe 新建一快捷方式至桌面,在桌面的快捷方式上點擊右鍵選擇屬性,修改“目標”爲 "C:\Program Files\Internet Explorer\iexplore.exe" -nomerge 通過此快捷方式啓動的瀏覽器不會共享會話
按照以上方式,更改了,再運行url,還是進入無權限頁面,發現跟session沒關係【後面會講跟session有關係的博文】,你使用360、谷歌測試,都是相同頁面。
進入debug調試……【當初debug時,漏掉一個方法,導致誤以爲是session的問題】
因爲咱們配置acegi的filter是:authenticationProcessingFilter,exceptionTranslationFilter,
,filterInvocationInterceptor這三個,其中第一個是身份認證的,debug首先進入第一個filter,但是實際上是進入AbstractProcessingFilter,而authenticationProcessingFilter是extends AbstractProcessingFilter,其中第一個filter的方法:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
if (!(request instanceof HttpServletRequest)) {
throw new ServletException( "Can only process HttpServletRequest");
}
if (!(response instanceof HttpServletResponse)) {
throw new ServletException( "Can only process HttpServletResponse");
}
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (requiresAuthentication(httpRequest, httpResponse)) {
if ( logger.isDebugEnabled()) {
logger.debug( "Request is to process authentication");
}
Authentication authResult;
try {
onPreAuthentication(httpRequest, httpResponse);
authResult = attemptAuthentication(httpRequest);
}
catch (AuthenticationException failed) {
// Authentication failed
unsuccessfulAuthentication(httpRequest, httpResponse, failed);
return;
}
// Authentication success
if ( continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
successfulAuthentication(httpRequest, httpResponse, authResult);
return;
}
chain.doFilter(request, response);
}
其中的分支點在於:requiresAuthentication(httpRequest, httpResponse)這個方法;根據名稱猜測到是否需要驗證的意思。當第一次運行時,這個爲true,然後進入其中身份認證。但是第二次執行時,就false,直接跳到下一個filter。
exceptionfilter這個就是捕捉錯誤的,不多談了。
然後再進入授權filter-filterInvocationInterceptor,獲取SecurityContextHolder.getContext().getAuthentication(),其中securitycontex中存在權限對象,然後直接進入decide投票方法。
那麼關鍵問題在於,爲啥securitycontext中保留上次的權限對象?
在第一個fiter認證後,securitycontext把已經通過認證對象保存進去successfulAuthentication,
SecurityContextHolder.getContext().setAuthentication(authResult);
這樣在filterInvocationInterceptor中,關鍵代碼如下:
if (!SecurityContextHolder.getContext().getAuthentication().isAuthenticated() || alwaysReauthenticate) {
try {
authenticated = this. authenticationManager.authenticate(SecurityContextHolder. getContext()
.getAuthentication());
}
catch (AuthenticationException authenticationException) {
throw authenticationException;
}
// We don't authenticated.setAuthentication(true), because each
// provider should do that
if ( logger.isDebugEnabled()) {
logger.debug( "Successfully Authenticated: " + authenticated.toString());
}
SecurityContextHolder. getContext().setAuthentication(authenticated);
}
else {
authenticated = SecurityContextHolder.getContext().getAuthentication();
if ( logger.isDebugEnabled()) {
logger.debug( "Previously Authenticated: " + authenticated.toString());
}
}
直接獲取其中的權限對象,進行投票匹配。
這篇博客主要分析了form認證的關鍵代碼,那下篇博客我們看看若添加了sessionfilter,會有什麼變化呢?