如何在 JSP / Servlet 中获取用户角色
Posted
技术标签:
【中文标题】如何在 JSP / Servlet 中获取用户角色【英文标题】:How to get user roles in a JSP / Servlet 【发布时间】:2008-12-05 15:14:32 【问题描述】:有没有什么方法可以获取一个字符串[] 与用户在 JSP 或 Servlet 中的角色?
我知道 request.isUserInRole("role1") 但我也想知道用户的所有角色。
我搜索了 servlet 源,似乎这是不可能的,但这对我来说似乎很奇怪。
那么……有什么想法吗?
【问题讨论】:
【参考方案1】:答案很混乱。
首先你需要找出你的 webapp 中 request.getUserPrincipal() 返回的类型。
System.out.println("type = " + request.getUserPrincipal().getClass());
假设返回 org.apache.catalina.realm.GenericPrincipal。
然后将 getUserPrincipal() 的结果转换为该类型并使用它提供的方法。
final Principal userPrincipal = request.getUserPrincipal();
GenericPrincipal genericPrincipal = (GenericPrincipal) userPrincipal;
final String[] roles = genericPrincipal.getRoles();
我说这会很乱。它也不是很便携。
【讨论】:
它返回类 org.jboss.security.SimplePrincipal 并且该类没有 getRoles() ......这很愚蠢......对不起,我应该提到:我正在使用 JBoss 4.2.3GA AS【参考方案2】:阅读所有可能的角色,或硬编码一个列表。然后运行 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);
【讨论】:
是的,我可以在用户登录时执行此操作...这是一个不错的技巧。但是,这在 JBoss 中是不可能的,比如 userPrincipal.getRoles(); ? 在编写 webapps 时,我总是避免使用任何特定于服务器的代码。您希望在 Tomcat 和 Resin 和 Jetty 等服务器之间保持可移植性。因此,您需要查看规范中是否有某些内容,或者从上下文中检索列表的方法。【参考方案3】:在 WebLogic 中,您可以这样做:
import weblogic.security.Security;
import weblogic.security.SubjectUtils;
...
private List<String> getUserRoles()
return Arrays.asList(SubjectUtils.getPrincipalNames(Security.getCurrentSubject()).split("/"));
请注意,列表中的第一个元素是用户名。
【讨论】:
我对此进行了测试,并在 Servlet 的上下文中工作。它是否也适用于 JAX-WS 上下文?【参考方案4】:在符合 JACC 的应用服务器上——理论上每个完整的 Java EE 平台实现——可以询问 Java SE Policy
以(几乎)对 Servlet 和 EJB 指定的任何类型的声明性安全约束进行可移植评估。我说几乎是因为 JACC 和 Policy#getPermissions(ProtectionDomain)
的 Javadoc 规范实际上都没有要求实现动态计算所有权限,大概是出于性能考虑,以及适应提供授权的提供者语句取决于附加上下文(远程地址、某个 HTTP GET 参数的值等)。尽管如此,getPermissions
与典型的预安装 JACC 提供程序一起使用通常应该是安全的。
以下示例演示了 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 Principals 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()
参考资料:
JSR-115 / JACC specification Using JACC to determine a caller's roles How Java EE translates web.xml constraints to Permission instances【讨论】:
以上是关于如何在 JSP / Servlet 中获取用户角色的主要内容,如果未能解决你的问题,请参考以下文章
使用 keycloak 在 servlet 应用程序中获取用户角色