如何正确使用isUserInRole(role)函数

15

防止用户角色执行某个操作。

  1. 示例1:只有"管理员"角色被允许执行销毁操作。
  2. 示例2:除了"guest"以外的任何角色都可以执行创建操作。

在一个实际情况中,我有这样一个需求:

public String delete() {
 if(FacesContext.getCurrentInstance().getExternalContext().isUserInRole("administrator"){
   //.....the action to perform
 }
 return "Denied";
}

我希望我能够在使用ManagedBeans的情况下使用EJB的注释@RolesAllowed()。所以问题是:有没有办法同时使用多个角色?是否有解决方法! 例如:如果一个操作必须允许3个角色(管理员,版主,经理),我必须这样做:

if (FacesContext.getCurrentInstance().getExternalContext().isUserInRole("administrator")
    || FacesContext.getCurrentInstance().getExternalContext().isUserInRole("manager") 
    || .....) {
  //....
}

而且要在所有方法上重现这种问题是一件很麻烦的事情。有几百种方法:(

3个回答

32

这需要在视图端进行控制。当您看到某些网站上有一个按钮,您没有足够的权限去按它,然后当你按下它时会看到一个令人生畏的错误页面,您不觉得这很烦人吗?

只需在用户拥有所需角色时才在视图中渲染按钮,否则完全隐藏它。

<h:commandButton value="Delete" action="#{bean.delete}" 
    rendered="#{request.isUserInRole('administrator')}" />

JSF 在 apply request values 阶段再次检查条件,因此不容易受到 CSRF 攻击。

如果要在单个视图中多次使用相同的条件,请考虑使用 <c:set> 来为它们赋予一个短别名。您甚至可以将它放置在某个主模板的顶部,以便所有子模板都可以使用它。

<c:set var="isPowerUser" value="#{request.isUserInRole('manager') or request.isUserInRole('administrator')}" scope="request" />
...
<h:commandButton rendered="#{isPowerUser}" />
...
<h:commandButton rendered="#{isPowerUser}" />

1
像往常一样进行智能实践!确实,收到“拒绝”的信息是非常烦人的。我已经使用渲染属性来显示管理员面板,如果角色是管理员等等。当然,在视图中这样做具有您提到的优点,但问题仍然存在:我被强制单独列举每个角色并使用或运算符!我错了吗? - Hanynowsky
1
这至少比 #{facesContext.externalContext.isUserInRole('administrator')} 更简洁 :) 如果您需要在同一视图中多次重复相同的条件,则还可以使用 <ui:param> 给它一个别名。请参见更新后的答案。 - BalusC
感谢BalusC!使用带有ui:param的主模板定义新角色并避免在托管bean中破解操作方法更为明智。现在对我来说它很好用,我只需要在视图中需要的地方应用新的角色别名即可。如果我真的想向未经授权的用户显示被拒绝的页面,@Bozho的方法也对我有效。 - Hanynowsky
2
@Rob:它是纯服务器端的,不是客户端或其他东西(它绝对不像JavaScript/CSS display=none/block),并且在JSF处理表单提交时被重新评估。另请参见例如https://dev59.com/IXI95IYBdhLWcg3w2h96#2120183的第5点。所以是的,您肯定漏掉了某些内容 :) - BalusC
@mabi:这是基于 ui:param 的原始答案中不经意留下的遗漏。请参考编辑历史记录。 - BalusC
显示剩余5条评论

7
你可以通过将逻辑移动到实用方法中来缩短它:
public class AuthorizationUtils {
    public static boolean isUserInRoles(String[] roles) {
        for (String role : roles) {
            if (FacesContext........isUserInRole(role)) {
                return true;
            }
        }

        return false;
    }
}

然后使用以下方式调用它:

if (AuthorizationUtils.isUserInRoles(new String[] {"administrator", "moderator"})) {
    ..
}

如果您正在使用CDI,您可以创建一个拦截器来处理@RolesAllowed注解。

这是我的问题的答案。虽然@BalusC提供了更好的实践方法。那么我可以在视图中使用您的实用程序方法,而不是破解操作方法吗?类似于: <h:commandButton value="Delete" action="#{bean.delete}" rendered="#{AuthorizationUtils.isUserInRole('administrator','operator','manager')}" /> 我想我在说废话!是吗? - Hanynowsky
我不确定EL是否允许这种静态调用,但是您可以创建一个叫做authBean的托管bean,并将该方法放在那里。 - Bozho
实用方法非常好用!不过,您介意我接受@BalusC的答案吗?因为这是我现在采用的答案。 - Hanynowsky

1

@Mediterran81:基本上你正在寻找基于bean方法的授权解决方案...你是如何实例化托管的bean的?你可能想引入一个简单的XML格式:

<bean class="">
 <method name="">
  <role> xyz</role>
 </method>
</bean>

通过实用程序类读取此XML,然后您需要做的唯一事情就是调用实用程序的静态方法来确定是否允许执行该方法。


我之前考虑过使用XML,但是被要求不要这样做,并且要尽量少编写代码来实现目标。在JSF环境中,我被要求更多地利用JSF视图功能来操作视图。然而,我投票支持你的答案,因为它描述了一种干净、流畅的方法来实现方法角色授权。谢谢ag112。 - Hanynowsky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接