2013-10-10 58 views
13

我爲Spring Web應用程序使用Spring Security的Spring-MVC。它包括用戶註冊頁面和私人用戶面板。我有它設置目前與以下網址模式:MVC攔截器vs Spring安全篩選器vs其他...?

  • whatever/myapp/login用戶登錄
  • whatever/myapp/register?step=1開始登記
  • whatever/myapp/account/**私人領域的意見(頁),而註冊後進程完全顯示
  • whatever/myapp/pending視圖
  • whatever/myapp/blocked賬戶被阻止的視圖
  • whatever/myapp/register/retry如果註冊失敗, llow重試

從本質上講,下面這些URL應該要求用戶身份驗證,即需要登錄:

  • whatever/myapp/account/**(私人區域頁)
  • whatever/myapp/pending(此頁有一個計時器設置爲重定向到/帳號/家)
  • whatever/myapp/register/retry

這是非常簡單交流請使用Spring安全性。但是,無論用戶通過Spring安全性進行身份驗證,根據用戶的當前帳戶狀態(存儲在我的數據庫中),私人區域頁面都應該可訪問或不可訪問。

更具體地說:如果用戶嘗試訪問私人區域(/account/**)中的任何內容,則應根據狀態顯示適當的視圖(重定向到適當的頁面)。我已經定義了這些狀態:

  • suspended - 涉及未決視圖
  • enabled - 允許完全訪問
  • disabled - 在這裏
  • retry_allowed無關 - 涉及重試視圖
  • blocked - 涉及到賬戶封鎖視圖

目前,我有一個MVC攔截器設置爲/account/**,它檢查用戶狀態並重定向到適當的頁面,但不知何故,我覺得這不是真正的理想或適當的解決方案,因爲我面臨奇怪的行爲,如多個控制器調用。 ..我也不太確定何時返回true/falsepreHandle()方法。以下是攔截器的代碼片段:

@Override 
public boolean preHandle(
    HttpServletRequest request, 
    HttpServletResponse response, 
    Object arg2) 
    throws Exception { 

IPanelUser pUser = (IPanelUser) SecurityContextHolder.getContext() 
     .getAuthentication().getPrincipal(); 

// check principal first and then load from DB 
// "suspended" is initial status upon registration 
if(pUser.getCustomer().getStatus() == CustomerStatus.Suspended.getCode()) { 

    // if suspended, load from DB and update status 
    Customer customer = this.customerService.getUserByUsername(pUser.getUsername()); 
    if(customer != null) 
     pUser.getCustomer().setStatus(customer.getStatus()); 

    // still suspended? redirect to pending 
    if(pUser.getCustomer().getStatus() == CustomerStatus.Suspended.getCode()) { 
     response.sendRedirect("../pending"); 
     return false; 
    } 
} 

if(pUser.getCustomer().getStatus() == CustomerStatus.Blocked.getCode()) { 

    // redirect to blocked page 
    response.sendRedirect("../blocked"); 
    SecurityContextHolder.clearContext(); 
    return false; 
} 

if(pUser.getCustomer().getStatus() == CustomerStatus.AllowRetry.getCode()) { 

    // redirect to CC submission page 
    response.sendRedirect("../register/retry"); 
    return false; 
} 

if(pUser.getCustomer().getStatus() == CustomerStatus.Enabled.getCode() || 
    pUser.getCustomer().getStatus() == CustomerStatus.Disabled.getCode()) { 

    // do nothing 
} 

return true; 
} 

這是一個有效的方法嗎?有其他建議嗎?

回答

21

所有選項都有效,它取決於你想要的抽象級別。

Filter,你只能訪問HttpServletRequestHttpServletResponse對象,所以你很再加上Servlet API。您也不(直接)訪問所有偉大的Spring功能,例如返回要呈現的視圖或ResponseEntity

HandlerInterceptor中,它又是一樣的。您可以直接在您無法訪問ModelAndViewpreHandle()中進行重定向或請求處理,也可以在postHandle()中設置一個您檢查的標誌。您將可以訪問ModelAndView,但不能訪問其他Spring MVC功能。

Spring Security是一個很好的選擇,但我發現它有很多配置,我不太喜歡它。

我最喜歡的最後一種選擇是使用AOP(您可以使用Spring Security或Shiro來完成此操作)。您創建了一個註釋,如@Private,並註釋了您的@Controller處理程序方法。您使用AOP來建議這些方法。該建議基本上檢查某個會話或請求屬性的標誌(授權與否)。如果你被允許,你繼續執行處理程序的方法,如果沒有,你會拋出一個UnauthorizedException(或類似的)。然後,您還爲該異常聲明@ExceptionHandler,您可以完全控制響應的生成方式:ModelAndView(和相關),ResponseEntity,使用@ResponseBody註解處理程序,直接編寫響應等。我覺得你像有更多的控制權,如果你想要的話。