【问题标题】:Using Spring Security in order to display different content for the same URL based upon whether or not the user is authenticated使用 Spring Security 以根据用户是否经过身份验证显示同一 URL 的不同内容
【发布时间】:2012-09-18 00:02:55
【问题描述】:

我使用 Spring MVC、Spring Security 和 Apache Tiles,但遇到以下问题:

我希望未经身份验证的用户登陆我网站的主页 URL(即www.mywebsite.com/),登录表单将显示给他们,以便他们可以进行身份​​验证从那里开始。

然后,一旦用户通过身份验证,我希望在网站的主页 URL(仍然是 www.mywebsite.com/)上向他们显示完全不同的页面内容,可能使用另一个模板/jsp .

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

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

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

【问题讨论】:

    标签: spring spring-mvc spring-security


    【解决方案1】:

    你应该这样做:

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

    【讨论】:

      【解决方案2】:

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

      首先,您可以使用 Spring Security 标签库根据用户是否经过正确身份验证,有条件地在您的视图模板中呈现内容。有关 Spring Security 标记库的更多信息是here。粗略地说,这会使您的视图模板看起来像:

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

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

      另一种方法是创建一个HandlerInterceptor 实现,它将所有请求转发到负责呈现登录页面的控制器,直到用户完全通过身份验证。您可以使用 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】:

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

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

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

        【讨论】:

        • 对不起。它并不像我想象的那么好。仔细阅读帖子后,我意识到要使此解决方案起作用,我必须集成我不想这样做的第三方类...
        【解决方案4】:

        你可以尝试使用

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

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

        【讨论】:

        • 谢谢约瑟夫。您的第二个回复与 Kpenchev 建议的非常相似,不幸的是,它并没有真正依赖 Spring Security。
        【解决方案5】:

        我能想到的一个解决方案是在您的 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");
                }
            }
        
        }
        

        【讨论】:

        • 感谢 kpentchev,这是一个有趣的想法。然而,这意味着我必须在我的控制器上复制这个逻辑......
        • 是的,从我的角度来看,这也是一个主要问题。也许这可以移动到一个过滤器/拦截器,重定向到您的网络应用程序的一个子部分,例如“/authorized/view”与“/unauthorized/view”。从那里,授权视图应该只指向其他授权视图等等......
        • 我确信 Spring 安全性允许以更简单的方式实现所需的行为。如果我发现相关内容,我会在这里发布。谢谢 KPentchev。
        • 如果您想向用户显示不同的对象集,比如说需要特定权限的项目子集,那么域对象安全 (ACL) 可能是您的最佳选择。
        猜你喜欢
        • 2016-07-04
        • 1970-01-01
        • 2015-08-09
        • 2011-03-27
        • 2021-12-18
        • 1970-01-01
        • 2021-09-24
        • 2014-12-20
        • 1970-01-01
        相关资源
        最近更新 更多