MVC拦截器与弹簧安全过滤器与其他东西



我正在为我的Web应用程序使用带有Spring Security的Spring-MVC。它包括用户注册页面和私人用户面板。我目前使用以下 URL 模式设置了它:

  • whatever/myapp/login用户登录
  • whatever/myapp/register?step=1开始注册
  • whatever/myapp/account/**私人区域视图(页面(
  • 注册后流程完成时显示whatever/myapp/pending视图
  • whatever/myapp/blocked帐户阻止视图
  • whatever/myapp/register/retry如果注册失败,请允许重试

从本质上讲,下面的这些 URL 应该需要用户身份验证,即需要登录:

  • whatever/myapp/account/**(私人区域页面(
  • whatever/myapp/pending(此页面有一个计时器设置为重定向到/account/home(
  • whatever/myapp/register/retry

使用Spring安全性实现这一点非常简单。但是,无论通过 Spring 安全性进行用户身份验证如何,私有区域页面都应该可以访问与否,具体取决于用户的当前帐户状态(存储在我的数据库中(。

更具体地说:如果用户尝试访问私人区域(/account/**(中的任何内容,则应根据状态向他显示适当的视图(重定向到适当的页面(。我定义了这些状态:

  • suspended - 与挂起的视图相关
  • enabled - 允许完全访问
  • disabled - 在这里无关紧要
  • retry_allowed - 与重试视图相关
  • blocked - 与帐户阻止的视图相关

目前,我有一个 MVC 拦截器设置要/account/**,它检查用户状态并重定向到适当的页面,但不知何故,我感觉到这不是这里真正理想或合适的解决方案,因为我面临着奇怪的行为,比如多控制器调用...... 而且我也不太确定何时在preHandle()方法中返回true/false。以下是拦截器中的代码片段:

@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;
}

.

这是一种有效的方法吗?有什么替代建议吗?

所有选项都是有效的,这取决于您想要的抽象级别。

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注释处理程序,直接编写响应等。我觉得如果你愿意的话,你可以有更多的控制权。

最新更新