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

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

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

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

所以…任何想法?

读入所有可能的角色,或硬编码列表。 然后迭代它运行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); 

答案很乱。

首先,您需要找出request.getUserPrincipal()在您的webapp中返回的类型。

  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(); 

我说它会变得凌乱。 它也不是很便携。

在WebLogic中,您可以使用:

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

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

在符合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 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: * 
    *
  • the remote user is unauthenticated
  • *
  • the remote user has not been associated with any roles declared within the search * scope
  • *
  • the method has not been called within a Servlet invocation context
  • *
*/ public static Set
getCallerWebRoles(String servletName) { // get current subject Subject subject = getSubject(); if (subject == null) { // unauthenticated return NO_ROLES; } Set 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 e = pc.elements(); if (!e.hasMoreElements()) { // nothing granted, hence no roles return NO_ROLES; } Set 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 getFromJaccPolicyContext(String key) { try { return (T) PolicyContext.getContext(key); } catch (PolicyContextException | IllegalArgumentException e) { return null; } } private Util() { } }

参考文献:

  • JSR-115 / JACC规范
  • 使用JACC确定呼叫者的角色
  • Java EE如何将web.xml约束转换为Permission实例