Java 如何在 JSP/Servlet 中获取用户角色

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/344117/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 13:40:38  来源:igfitidea点击:

How to get user roles in a JSP / Servlet

javaauthenticationjspservletsjboss

提问by AlfaTeK

Is there any way to get a String[] with the roles a user has in the JSP or Servlet?

有没有办法获得一个 String[] 与用户在 JSP 或 Servlet 中的角色?

I know about request.isUserInRole("role1") but I also want to know all the roles of the user.

我知道 request.isUserInRole("role1") 但我也想知道用户的所有角色。

I searched the servlet source and it seems this is not possible, but this seems odd to me.

我搜索了 servlet 源,似乎这是不可能的,但这对我来说似乎很奇怪。

So... any ideas?

所以……有什么想法吗?

采纳答案by Josh

Read in all the possible roles, or hardcode a list. Then iterate over it running the isUserInRole and build a list of roles the user is in and then convert the list to an array.

读入所有可能的角色,或硬编码一个列表。然后迭代它运行 isUserInRole 并构建用户所在的角色列表,然后将该列表转换为数组。

String[] allRoles = {"1","2","3"};
HttpServletRequest request = ... (or from method argument)
List userRoles = new ArrayList(allRoles.length);
for(String role : allRoles) {
 if(request.isUserInRole(role)) { 
  userRoles.add(role);
 }
}

// I forgot the exact syntax for list.toArray so this is prob wrong here
return userRoles.toArray(String[].class);

回答by Steve McLeod

The answer is messy.

答案很乱。

First you need to find out what type request.getUserPrincipal() returns in your webapp.

首先,您需要找出 request.getUserPrincipal() 在您的 web 应用程序中返回的类型。

    System.out.println("type = " + request.getUserPrincipal().getClass());

Let's say that returns org.apache.catalina.realm.GenericPrincipal.

假设返回 org.apache.catalina.realm.GenericPrincipal。

Then cast the result of getUserPrincipal() to that type and use the methods it provides.

然后将 getUserPrincipal() 的结果转换为该类型并使用它提供的方法。

    final Principal userPrincipal = request.getUserPrincipal();
    GenericPrincipal genericPrincipal = (GenericPrincipal) userPrincipal;
    final String[] roles = genericPrincipal.getRoles();

I said it was going to be messy. It's not very portable either.

我说那会很乱。它也不是很便携。

回答by SuperPiski

In WebLogic you can do it with:

在 WebLogic 中,您可以使用:

import weblogic.security.Security;
import weblogic.security.SubjectUtils;
...
private List<String> getUserRoles()  {
    return Arrays.asList(SubjectUtils.getPrincipalNames(Security.getCurrentSubject()).split("/"));
}

Note that the first element on the list is the user name.

请注意,列表中的第一个元素是用户名。

回答by Uux

On JACC-compliant application servers -- in theory every Full Java EE Platform implementation -- the Java SE Policycan be interrogated for (almost) portable evaluation of any type of declarative security constraint specified by Servlet and EJB. I say almostbecause neither JACC nor the Javadoc spec of Policy#getPermissions(ProtectionDomain)actually requires that the implementation compute all permissions on the fly, presumably due to performance considerations, as well as to accommodate for providers whose rendering of authorization statements depends on additional context (remote address, value of a certain HTTP GET parameter, etc.). Nonetheless, getPermissionsshould normally be safe to use with the typical pre-installed JACC provider.

在符合 JACC 的应用服务器上——理论上每个完整的 Java EE 平台实现——Java SEPolicy可以被询问(几乎)可移植评估由 Servlet 和 EJB 指定的任何类型的声明性安全约束。我这么说几乎是因为 JACC 和 Javadoc 规范Policy#getPermissions(ProtectionDomain)实际上都不需要实现动态计算所有权限,大概是出于性能考虑,以及适应提供者的授权语句的呈现取决于附加上下文(远程地址、值某个 HTTP GET 参数等)。尽管如此,getPermissions与典型的预安装 JACC 提供程序一起使用通常应该是安全的。

The following example demonstrates Servlet role assignment testing:

以下示例演示了 Servlet 角色分配测试:

package com.example;

import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Policy;
import java.security.Principal;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

import javax.security.auth.Subject;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
import javax.security.jacc.WebRoleRefPermission;

public final class Util {


    private static final Set<String> NO_ROLES = Collections.emptySet();
    private static final Permission DUMMY_WEB_ROLE_REF_PERM = new WebRoleRefPermission("", "dummy");

    /**
     * Retrieves the declared Servlet security roles that have been mapped to the {@code Principal}s of
     * the currently authenticated {@code Subject}, optionally limited to the scope of the Servlet
     * referenced by {@code servletName}.
     * 
     * @param servletName
     *            The scope; {@code null} indicates Servlet-context-wide matching.
     * @return the roles; empty {@code Set} iff:
     *         <ul>
     *         <li>the remote user is unauthenticated</li>
     *         <li>the remote user has not been associated with any roles declared within the search
     *         scope</li>
     *         <li>the method has not been called within a Servlet invocation context</li>
     *         </ul>
     */
    public static Set<String> getCallerWebRoles(String servletName) {
        // get current subject
        Subject subject = getSubject();
        if (subject == null) {
            // unauthenticated
            return NO_ROLES;
        }
        Set<Principal> principals = subject.getPrincipals();
        if (principals.isEmpty()) {
            // unauthenticated?
            return NO_ROLES;
        }
        // construct a domain for querying the policy; the code source shouldn't matter, as far as
        // JACC permissions are concerned
        ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), null, null,
                principals.toArray(new Principal[principals.size()]));
        // get all permissions accorded to those principals
        PermissionCollection pc = Policy.getPolicy().getPermissions(domain);
        // cause resolution of WebRoleRefPermissions, if any, in the collection, if still unresolved
        pc.implies(DUMMY_WEB_ROLE_REF_PERM);
        Enumeration<Permission> e = pc.elements();
        if (!e.hasMoreElements()) {
            // nothing granted, hence no roles
            return NO_ROLES;
        }
        Set<String> roleNames = NO_ROLES;
        // iterate over the collection and eliminate duplicates
        while (e.hasMoreElements()) {
            Permission p = e.nextElement();
            // only interested in Servlet container security-role(-ref) permissions
            if (p instanceof WebRoleRefPermission) {
                String candidateRoleName = p.getActions();
                // - ignore the "any-authenticated-user" role (only collect it if your
                // application has actually declared a role named "**")
                // - also restrict to the scope of the Servlet identified by the servletName
                // argument, unless null
                if (!"**".equals(candidateRoleName) && ((servletName == null) || servletName.equals(p.getName()))
                        && ((roleNames == NO_ROLES) || !roleNames.contains(candidateRoleName))) {
                    if (roleNames == NO_ROLES) {
                        roleNames = new HashSet<>();
                    }
                    roleNames.add(candidateRoleName);
                }
            }
        }
        return roleNames;
    }

    private static Subject getSubject() {
        return getFromJaccPolicyContext("javax.security.auth.Subject.container");
    }

    @SuppressWarnings("unchecked")
    private static <T> T getFromJaccPolicyContext(String key) {
        try {
            return (T) PolicyContext.getContext(key);
        }
        catch (PolicyContextException | IllegalArgumentException e) {
            return null;
        }
    }

    private Util() {
    }

}


References:

参考: