2013-11-02 27 views
6

我正在使用GlassFish服务器4.0,我已将不同的权限/角色分配给不同的用户。如何让每个用户根据其在JAAS中的权限/角色在特定位置访问资源?

用户可能拥有多个权限/角色。例如,管理员用户可能与ROLE_ADMIN(执行管理任务)和ROLE_USER(作为注册用户执行任务)相关联。

在我的web.xml中,配置如下。

<security-constraint> 
    <display-name>AdminConstraint</display-name> 
    <web-resource-collection> 
     <web-resource-name>ROLE_ADMIN</web-resource-name> 
     <description/> 
     <url-pattern>/admin_side/*</url-pattern> 
    </web-resource-collection> 
    <auth-constraint> 
     <description/> 
     <role-name>ROLE_ADMIN</role-name> 
    </auth-constraint> 
    <user-data-constraint> 
     <description/> 
     <transport-guarantee>CONFIDENTIAL</transport-guarantee> 
    </user-data-constraint> 
</security-constraint> 

<security-constraint> 
    <display-name>UserConstraint</display-name> 
    <web-resource-collection> 
     <web-resource-name>ROLE_USER</web-resource-name> 
     <description/> 
     <url-pattern>/user_side/*</url-pattern> 
    </web-resource-collection> 
    <auth-constraint> 
     <description/> 
     <role-name>ROLE_USER</role-name> 
    </auth-constraint> 
    <user-data-constraint> 
     <description/> 
     <transport-guarantee>CONFIDENTIAL</transport-guarantee> 
    </user-data-constraint> 
</security-constraint> 

<login-config> 
    <!--<auth-method>DIGEST</auth-method>--> 
    <auth-method>FORM</auth-method> 
    <realm-name>projectRealm</realm-name> 
    <form-login-config> 
     <form-login-page>/utility/Login.jsf</form-login-page> 
     <form-error-page>/utility/ErrorPage.jsf</form-error-page> 
    </form-login-config> 
</login-config> 

<security-role> 
    <description/> 
    <role-name>ROLE_ADMIN</role-name> 
</security-role> 

<security-role> 
    <description/> 
    <role-name>ROLE_USER</role-name> 
</security-role> 

这工作得很好。


有两个URL模式/admin_side/*/user_side/*。管理员有两个角色ROLE_ADMINROLE_USER

当管理员使用权限ROLE_USER登录时,只有位于/user_side/*中的资源应该被访问。位于/admin_side/*的资源应该被禁止访问,因为管理员以注册用户身份登录,而不是以管理员身份登录。

到现在为止我的情况是,当管理员使用任何权限登录时,两个位置的资源都可以被访问,这是完全非法的。这是因为系统能够为该特定用户找到两个权威机构。

如何让每个用户根据其权限/角色访问特定位置的资源?


认证过滤器:

@WebFilter(filterName = "SecurityCheck", urlPatterns = {"/jass/*"}) 
public final class SecurityCheck implements Filter 
{ 
    private FilterConfig filterConfig = null; 

    @Resource(mappedName="jms/destinationFactory") 
    private ConnectionFactory connectionFactory; 
    @Resource(mappedName="jms/destination") 
    private Queue queue; 
    @EJB 
    private final UserBeanLocal userService=null; 

    public SecurityCheck() {} 

    private void sendJMSMessageToDestination(String message) throws JMSException 
    { 
     Connection connection = null; 
     Session session = null; 

     try 
     { 
      connection = connectionFactory.createConnection(); 
      session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 
      MessageProducer messageProducer = session.createProducer(queue); 
      TextMessage textMessage = session.createTextMessage(); 
      textMessage.setText(message); 
      messageProducer.send(textMessage); 
     } 
     finally 
     { 
      if(session!=null){session.close();} 
      if(connection!=null){connection.close();} 
     } 
    } 

    private void doBeforeProcessing(ServletRequest request, ServletResponse response) throws IOException, ServletException 
    { 
     HttpServletRequest httpServletRequest=(HttpServletRequest)request; 
     httpServletRequest.login(httpServletRequest.getParameter("userName"), httpServletRequest.getParameter("password")); 
    } 

    private void doAfterProcessing(ServletRequest request, ServletResponse response) throws IOException, ServletException, JMSException 
    { 
     HttpServletRequest httpServletRequest=(HttpServletRequest)request; 
     HttpServletResponse httpServletResponse=(HttpServletResponse)response; 
     ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); 
     Map<String, Object> sessionMap = externalContext.getSessionMap(); 

     if(httpServletRequest.isUserInRole("ROLE_USER")) 
     { 
      sendJMSMessageToDestination(httpServletRequest.getLocalName()); 
      UserTable userTable = userService.setLastLogin(httpServletRequest.getParameter("userName")); 
      userTable.setPassword(null); 
      sessionMap.put("userName", userTable!=null?userTable.getFirstName():"Unknown"); 
      sessionMap.put("user", userTable); 

      httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 
      httpServletResponse.setHeader("Pragma", "no-cache"); 
      httpServletResponse.setDateHeader("Expires", 0); 
      httpServletResponse.sendRedirect("../user_side/Home.jsf"); 
     } 
     else if(httpServletRequest.isUserInRole("ROLE_ADMIN")) 
     { 
      sendJMSMessageToDestination(httpServletRequest.getLocalName()); 
      UserTable userTable = userService.setLastLogin(httpServletRequest.getParameter("userName")); 
      userTable.setPassword(null); 
      sessionMap.put("adminName", userTable!=null?userTable.getFirstName():"Unknown"); 
      sessionMap.put("user", userTable); 

      httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 
      httpServletResponse.setHeader("Pragma", "no-cache"); 
      httpServletResponse.setDateHeader("Expires", 0); 
      httpServletResponse.sendRedirect("../admin_side/Home.jsf"); 
     } 
    } 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
    { 
     try 
     { 
      doBeforeProcessing(request, response); 
     } 
     catch (Exception e) 
     { 
      HttpServletResponse httpServletResponse=(HttpServletResponse)response; 
      //FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "Incorrect user name and/or password. Access denied.")); 
      httpServletResponse.sendRedirect("../utility/Login.jsf"); 
      return; 
     } 

     chain.doFilter(request, response); 

     try 
     { 
      doAfterProcessing(request, response); 
     } 
     catch (JMSException ex) 
     { 
      Logger.getLogger(SecurityCheck.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 

    //The rest of the filter. 
} 

如果你需要看其他的东西在我的应用程序的话,请让我知道。

+0

你到底是如何以注册用户身份登录管理员的?如果一个特定的用户有多个角色,那么实际上没有办法只使用其中的一个登录。所以整个问题很混乱。 – BalusC

+0

这是一个验证用户身份的过滤器。过滤器映射到URL模式 - '/ jass/*'(错误地键入,应该是'/ jaas/*')。它指示一个目录,其中只有一个页面 - 调用JSF页面上的登录按钮时(通过其相应的JSF托管bean)调度请求的'temp.jsp'。有没有办法一次作为管理员登录和一次使用相同的ID /密码的用户登录?我也觉得如此,但认为容器可能支持一些机制来做到这一点。我看了一些教程,但一无所知。 – Tiny

回答

1

您似乎认为,当用户有多个角色时,该用户可以同时使用这些角色中的一个角色登录。这不是真的。用户没有以每个角色为基础登录。用户以每个用户为基础登录。如果用户有多个角色,那么他们将在整个登录会话中使用并应用全部

实际上,它是而不是可能让用户在整个会话中只选择和使用其中一个分配的角色。到目前为止,听起来太像你的管理员不应该把ROLE_USER放在第一位。但是这使得现实世界没有多大意义。角色不应该“扩展”现有角色。即ROLE_ADMIN不应复制与ROLE_USER相同的限制,然后在其上添加更多内容。不,它应该完全代表“更多”。然后,管理员用户只需分配这两个角色(您正确地完成了该部分)。否则,最终会在用户和管理员可以访问/使用的地方遍历代码进行重复检查。然后,我不是在谈论第三个可能需要在代码中进行三重检查的角色。你需要在所有地方编辑现有的代码。

如果您希望以编程方式在运行时切换角色,也许是因为您希望能够以普通用户的身份“预览”该网站(例如,当仅管理部分/按钮时,检查网站的外观隐藏的),那么基本上有两种选择:

  1. 设置一些标志作为会话属性或可能作为请求参数,并且对这些代码检查。例如。

    <h:form> 
        <h:selectBooleanCheckbox value="#{sessionScope.preview}"> 
         <f:ajax render="@all" /> 
        </h:selectBooleanCheckbox> 
    </h:form> 
    

    (注意:该代码是原来的样子,#{sessionScope}一个隐含的EL变量参照ExternalContext#getSessionMap();无需其它辅助bean)

    然后在主tamplate:

    <c:set var="userIsAdmin" value="#{request.isUserInRole('ROLE_ADMIN') and not preview}" scope="request" /> 
    

    并在包含一些管理员特定的东西的目标视图中:

    <h:commandButton value="Some awesome admin button" rendered="#{userIsAdmin}" /> 
    

  2. 以普通用户身份执行程序化登录。您可以使用HttpServletRequest#login()以编程方式触发容器管理的身份验证。通过这种方式,管理员可以“模拟”不同的用户并浏览站点,就好像他已经以特定用户身份登录一样。例如。在会话范围的bean:

    public void runAs(User user) { 
        // ... 
        try { 
         request.login(user.getUsername(), user.getPassword()); 
         originalUser = currentUser; 
         currentUser = user; 
         // ... 
        } catch (ServletException e) { 
         // ... 
        } 
    } 
    
    public void releaseRunAs() { 
        // ... 
        try { 
         request.login(originalUser.getUsername(), originalUser.getPassword()); 
         currentUser = originalUser; 
         // ... 
        } catch (ServletException e) { 
         // ... 
        } 
    } 
    

    你甚至可以通过保持在LILO以前所有的用户进行扩展(后进后出)队列中的会话范围。像Apache Shiro这样的大多数安全框架都有builtin APIs

+0

我目前坚持“*每用户基础*”方法,而不是不必要地进入复杂性。主要是,我想知道它是否受到容器的支持,开箱即用,我完全厌倦了来回翻看Oracle文档。:)现在我去掉了我很大的疑问。谢谢。 – Tiny

1

我觉得得到你要的是非常小心这种行为,可能添加其他管理员帐户,而不是并从该帐户的ROLE_USER的方式。

+0

在问这个问题之前,我也认为这只是这个问题的答案:)。这样做,但是我们不能说一个用户可以拥有多个权限/角色,因为用户需要拥有多个对应于多个权限/角色的帐户。虽然单个用户可能拥有多个具有不同权限/角色的帐户,但是**系统都将被系统视为不同的用户** :)。 – Tiny

相关问题