我正在将Spring-MVC与Spring Security一起用于我的Web应用程序。它包括用户注册页面和私人用户面板。我现在设置了以下网址模式:
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
- 与帐户被屏蔽的视图相关目前,我有/account/**
的MVC拦截器设置,用于检查用户状态,并重定向到适当的页面,但不知怎的,我觉得这不是理想的或适当的解决方案,因为我' m面临奇怪的行为,比如多个控制器调用...而且我还不确定何时在true
方法中返回false
/ preHandle()
。这是拦截器的代码片段:
@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;
}
。
这是一种有效的方法吗?还有其他建议吗?
答案 0 :(得分:21)
所有选项都有效,这取决于您想要的抽象级别。
在Filter
中,您只能访问HttpServletRequest
和HttpServletResponse
个对象,因此您非常适合使用Servlet
API。您也没有(直接)访问所有出色的Spring功能,例如返回要呈现的视图或ResponseEntity
。
在HandlerInterceptor
中,它再次变得更加相同。您可以直接在无法访问preHandle()
的{{1}}中进行重定向或请求处理,也可以设置您在ModelAndView
中签入的标记。您可以访问postHandle()
但不能访问其他一些Spring MVC功能。
Spring Security是一个不错的选择,但我发现它有很多我不太喜欢的配置。
我最喜欢的最后一个选择是使用AOP(你也可以使用Spring Security或Shiro)。您可以创建类似ModelAndView
的注释,并注释@Private
处理程序方法。您使用AOP建议这些方法。该建议基本上检查一些会话或请求属性的标志(授权与否)。如果允许,则继续执行处理程序方法,否则,抛出@Controller
(或类似)。然后,您还可以为该异常声明@ExceptionHandler
,您可以完全控制响应的生成方式:{{1}}(和相关),UnauthorizedException
,使用{注释处理程序{1}},直接写回复等等。如果你愿意,我觉得你有更多的控制权。