MVC拦截器 vs 弹簧安全过滤器 vs 其他东西...?

我正在将Spring-MVC与Spring Security一起使用,用于我的Web应用程序。它包括用户注册页面和私人用户面板。我目前已使用以下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 security进行身份验证,私人区域页面都应该可以访问,具体取决于用户的当前帐户状态(存储在我的数据库中)。

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

  • suspended- 与待处理视图相关
  • enabled- 允许完全访问
  • disabled- 此处不相关
  • retry_allowed- 与重试视图相关
  • blocked- 与帐户阻止视图相关

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

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

.

这是一种有效的方法吗?还有其他建议吗?


答案 1

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

在 中,您只能访问 和 对象,因此您与 API 非常耦合。您也无法(直接)访问所有出色的Spring功能,例如返回要渲染的视图或.FilterHttpServletRequestHttpServletResponseServletResponseEntity

在 a 中,它又是更相同的。您可以直接在无法访问的地方进行重定向或请求处理,或者设置您签入的标志。您将可以访问但不能访问其他一些Spring MVC功能。HandlerInterceptorpreHandle()ModelAndViewpostHandle()ModelAndView

Spring Security是一个很好的选择,但我发现它有很多我不太喜欢的配置。

最后一个我最喜欢的选择是使用AOP(您也可以使用Spring Security或Shiro执行此操作)。您可以创建一个类似注释的注释,并对处理程序方法进行注释。您可以使用 AOP 来建议这些方法。该建议基本上检查某个会话或请求属性的标志(授权与否)。如果允许,则继续执行处理程序方法,否则,将抛出一个(或类似方法)。然后,您还可以为该异常声明一个@ExceptionHandler,在该异常中,您几乎可以完全控制响应的生成方式:a(和相关),a,注释处理程序,直接编写响应等。我觉得你有更多的控制权,如果你想要的话。@Private@ControllerUnauthorizedExceptionModelAndViewResponseEntity@ResponseBody


答案 2

推荐