使用Spring Security根据用户是否经过身份验证,显示相同URL的不同内容

时间:2012-09-26 11:13:08

标签: spring spring-mvc spring-security

我使用Spring MVC,Spring Security和Apache Tiles,我有以下问题:

我希望未经身份验证的用户登陆我网站的主页网址(即www.mywebsite.com/),其中会向他们显示一个登录表单,以便他们可以从那里验证。

然后,一旦用户通过身份验证,我希望在网站的主页网址(仍为www.mywebsite.com/)上显示完全不同的页面内容,可能使用其他模板/ JSP。

我想要实现的基本上是能够根据用户是否经过身份验证来显示相同​​URL的不同内容 - 所有这些都使用Spring安全性和Spring MVC。

我研究过Spring Security,但无法找到上述问题的解决方案。其他人遇到了类似的问题(参见:Spring security - same page to deliver different content based on user role

任何人都可以提供有关如何实现这一点的指示或建议吗?

5 个答案:

答案 0 :(得分:3)

我能想到的一个解决方案是从请求中检入MVC控制器中的用户主体,如果已经过身份验证/有角色返回一个ModelAndView,否则返回另一个:

@Controller
public class MyController{

    public ModelAndView doSomething(HttpServletRequest request, HttpServletResponse response){
        if(request.getUserPrincipal() != null && request.isUserInRole("someRole"){
            return new ModelAndView("view1");
        } 
        else {
            return new ModelAndView("view2");
        }
    }

}

答案 1 :(得分:2)

Spring论坛的成员为我提供了一个漂亮而优雅的解决方案。这是:

@RequestMapping("/")
@PreAuthorize("isAuthenticated()")
public String authenticatedHomePage() {
    return "authenticatedHomePage";
}

@RequestMapping("/")
public String homePage() {
    return "homePage";
}

这很好,因为它依赖于Spring Security。见这里(blog post

答案 2 :(得分:1)

我可以想到几种实现你想要的方法。

首先,您可以使用Spring Security标记库有条件地呈现View模板中的内容,具体取决于用户是否经过了正确的身份验证。有关Spring Security标记库的更多信息是here。粗略地说,这将使您的View模板看起来像:

if(user is authenticated)
     render content for authenticated user
else
     render log-in form

然而,感觉有点生硬,因为无论用户是否经过正确的身份验证,您的控制器始终都会创建模型。每当您想要显示登录表单时,您还需要在View模板中使用此逻辑。

另一种方法是创建一个HandlerInterceptor实现,将所有请求转发给负责呈现登录页面的Controller,直到用户完全通过身份验证。您可以使用HandlerInterceptor的preHandle()方法执行此操作:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyHandlerInterceptor implements HandlerInterceptor
{

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
    SecurityContext sc = SecurityContextHolder.getContext();
    boolean userAuthenticated = true;
    /* Some logic in here to determine if the user is correctly authenticated */

    if(!userAuthenticated)
    {
        request.getRequestDispatcher("/login").forward(request, response);
        return false;
    }

    return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
{

}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception
{

}}

然后,您可以配置Spring MVC以将HandlerInterceptor实现映射到您需要此功能的URL。这样可以避免在所有控制器上复制逻辑,并且很容易测试。

答案 3 :(得分:0)

你可以尝试使用

<security:authorize access=”isAnonymous()”>
not authenticated page
</security:authorize>
<security:authorize access=”isAuthenticated()”>
authenticated page
</security:authorize>

或者您可以在控制器中返回“redirect:page_for_not_auth”作为视图名称,以将响应重定向到另一个处理未经验证的请求的控制器/方法。

答案 4 :(得分:0)

你应该这样做:

@RequestMapping("/")
public String generalHomePage() {
    ...
}

@RequestMapping("/")
@PreAuthorize("isAuthenticated()")
public String secureHomePage() {
    ...
}