如何让每个用户根据他们在JAAS中的权限/角色访问特定位置的资源? [英] How to make each user access resources at a specific location according to their authority/role in JAAS?

查看:142
本文介绍了如何让每个用户根据他们在JAAS中的权限/角色访问特定位置的资源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用GlassFish服务器4.0,其中我为不同的用户分配了不同的权限/角色。

I'm using GlassFish server 4.0 in which I have assigned different authorities/roles to different users.

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

A user may have multiple authorities/roles. For example, an admin user may be associated with ROLE_ADMIN (to perform administrative tasks) and ROLE_USER (to perform tasks as a registered 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>

这很好用。

有两种网址格式 / admin_side / * / user_side / * 。管理员有两个角色 ROLE_ADMIN ROLE_USER

There are two URL patterns /admin_side/* and /user_side/*. The administrator has two roles ROLE_ADMIN and ROLE_USER.

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

When the administrator logs in using the authority ROLE_USER, the only resources located in /user_side/* should be accessed. The resources located in /admin_side/* should be forbidden from being accessed because the admin is logged in as a registered user and not as an admin.

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

Until now what happens in my case is that when admin logs in using any of the authorities, the resources in both the locations can be accessed which is perfectly illegal. It is because the system is able to locate both the authorities for that particular user.

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

How to have each user access resources at a specific location according to their authority/role?

身份验证过滤器:

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

如果您需要查看我的申请中的其他内容,请请告诉我。

推荐答案

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

You seem to think that when an user has multiple roles, then this user can login using only one of those roles simultaneously. This is not true. Users are not logged in on a per-role basis. Users are logged in on a per-user basis. If an user has multiple roles, then they will all be used and applied throughout the entire login session.

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

Actually, it is not possible to let an user pick and use only one of the assigned roles throughout the session. So far it sounds too much like that your admin shouldn't have the ROLE_USER in first place. But this makes in real world little sense. Roles aren't supposed to "extend" existing roles. I.e. ROLE_ADMIN shouldn't copy the same restrictions as ROLE_USER and then add some more on top of that. No, it should solely represent exactly that "some more". Admin users are then just assigned the both roles (you did that part correctly). Otherwise you end up with duplicate checks throughout the code at places which may be accessed/used by both an user and an admin. And then I'm not talking about a third role above this which may require triple checks in the code. You'd need to edit the existing code over all place.

如果您希望以编程方式在运行时切换角色,可能是因为您希望能够预览网站作为普通用户(例如,当隐藏管理员部分/按钮时检查网站的外观),然后基本上有两个选项:

If you'd like to programmatically toggle roles during runtime, perhaps because you'd like being able to "preview" the site as a regular user (e.g. checking how the site look like when admin-only sections/buttons are hidden), then there are basically two options:


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

  1. Set some flag as session attribute or perhaps as request parameter and have the code check on that. E.g.

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

(注意:代码是原样,#{ sessionScope} 是一个隐含的EL变量,引用 ExternalContext#getSessionMap();不需要额外的辅助bean)

(note: the code is as-is, #{sessionScope} is an implicit EL variable referring ExternalContext#getSessionMap(); no additional backing bean necessary)

然后在主模板中:

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

在目标视图中包含一些特定于管理员的内容:

And in the target views containing some admin specific stuff:

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





  • 以普通用户身份执行程序化登录。你可以使用 HttpServletRequest#login() 以编程方式触发容器管理的身份验证。这样,管理员可以模仿不同的用户并浏览该网站,就像他以特定用户身份登录一样。例如。在会话范围内的bean:


  • Perform programmatic login as a regular user. You can use HttpServletRequest#login() to programmatically trigger container managed authentication. This way an admin can "impersonate" a different user and browse the site as if he's logged-in as the particular user. E.g. in a session scoped 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这样的大多数安全框架都有内置API

    You can even extend it by holding all previous users in a LILO (last in, last out) queue in the session scope. Most security frameworks like Apache Shiro have builtin APIs for this.

    这篇关于如何让每个用户根据他们在JAAS中的权限/角色访问特定位置的资源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆