有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何将JAAS授权检查委托给Shiro?

我正在开发一个需要基于对象的身份验证和授权的服务器端应用程序。我喜欢Shiro的简单性,但为了与JAAS兼容,我编写了一个LoginModule,它使用ApacheShiro作为底层机制

但我的问题是,我找不到将JAAS授权检查委托给Shiro的方法。我怎样才能做到这一点


共 (1) 个答案

  1. # 1 楼答案

    注:答案涉及通过标准安全框架将外部授权系统与JVM集成的一般情况。这不是Shiro或JMX特有的,因为我对它们都不熟悉


    从概念上讲,您似乎是在策略决策点(PDP)之后,即授权查询(“实体X允许做Y吗?”)进行评估,也就是说。JDK提供了以下几种:

    1. 有效的^{},特别是它的checkXXX组方法
    2. ^{}类,尤其是它的implies(Permission)方法
    3. 有效的^{}的关键implies(ProtectionDomain, Permission)方法
    4. 其次是{a4}、{a5}、{a6}和{a7}的{}方法

    为了以递增粒度定制概念PDP的功能,可以覆盖上述任何方法。应该指出的是,JAAS并没有真正带来自己的PDP(与其名称相反);相反,它为域和策略提供了means,以支持基于主体的查询,此外还提供了源代码的原始信任因子。因此,在我看来,您保持“JAAS兼容”的要求基本上转化为希望使用(原始加JAAS)JavaSE授权模型,即沙箱,我怀疑这不是您想要的。当标准模型被认为过于低级和/或性能密集时,往往会使用Shiro等框架;换句话说,当授权逻辑不需要为给定的一组信任因子评估每个堆栈帧时,因为这些因子通常对上下文不敏感。根据我假设的有效性,有三种主要情况需要检查:

    1. 授权是AccessControlContext独立的。Shiro native authorization attributes(SNAA),不管它们是什么,都适用于整个线程。代码来源无关紧要
    2. 代码起源很重要,要求使用沙箱。SNAA仍然是AccessControlContext独立的
    3. 代码起源和SNAA都是相关的,并且AccessControlContext-依赖于

    一,。仅基于SNAAs的授权

    1. 无论你认为合适与否,都要管理身份验证。如果希望继续使用JAAS javax.security.authSPI进行身份验证,请忘记建立一个标准Subject作为身份验证结果,而是直接将特定于Shiro的一个绑定到线程本地存储。通过这种方式,您可以更方便地访问SNAAs,并避免使用AccessControlContext(并遭受潜在的performance penalty)进行检索

    2. 子类SecurityManager,重写至少两个checkPermission方法,以便

      1. 如有必要,将Permission参数翻译成Shiro的PDP(SPDP)在
      2. 使用线程本地SNAAs和权限委托给SPDP(如果SPDP发出访问拒绝信号,则抛出SecurityException

      接收重载的安全上下文可能会忽略相应的参数。在应用程序初始化时,实例化并安装(System::setSecurityManager)您的实现


    二,。混合授权,将源代码与不区分上下文的SNAAs结合起来

    1. 以你认为合适的方式管理认证;再次将特定于Shiro的Subject与线程本身关联起来
    2. 子类SecurityManager,至少重写两个checkPermission方法,这一次,它们将委托给SPDP和/或重写的实现(后者反过来相应地调用当前或提供的访问控制上下文上的checkPermission)。对于任何给定的许可,应咨询哪一个(或多个)以及以何种顺序进行咨询,这当然取决于实施情况。当两者都被调用时,应该首先查询SPDP,因为它的响应速度可能比访问控制上下文更快
    3. 如果SPDP要额外处理eva根据对源自特定位置和/或一组代码签名者的代码授予的权限,您还必须将Policy子类化,实现implies(ProtectionDomain, Permission),这样,就像上面的SecurityManager::checkPermission,它将一些可理解的域表示(通常仅其CodeSource)和权限参数传递给SPDP,但从逻辑上讲,而不是SNAA。该实现应该尽可能高效,因为它将在checkPermission时间为每个访问控制上下文的每个域调用一次。实例化并安装(Policy::setPolicy)您的实现

    三,。混合授权,将源代码与SNAAs相结合,两者都与上下文相关

    1. 无论你认为合适与否,都要管理身份验证。不幸的是,在本例中,主题处理部分并不像创建ThreadLocal那么简单

    2. 子类化、实例化并安装一个Policy,它执行SecurityManager::checkPermissionPolicy::implies的组合职责,如第二种情况中单独描述的那样

    3. 实例化并安装一个标准SecurityManager

    4. 创建一个ProtectionDomain子类,能够存储和公开SNAAs

    5. 作者1a^{}

      1. 是用SNAS构建的

      2. 实现combine(ProtectionDomain[], ProtectionDomain[]),以便

        1. 它用自定义实现的等效实例替换第一个(当前上下文)数组参数的域
        2. 然后将第二个(指定的或继承的上下文)参数的参数(如果有的话)按原样附加到前者;最后
        3. 返回连接

      Policy::implies一样,实现应该是高效的(例如通过消除重复),因为每次调用getContextcheckPermission{}方法时都会调用它

    6. 身份验证成功后,创建一个新的AccessControlContext来包装当前的DomainCombiner,以及一个自定义的DomainCombiner实例,反过来包装SNAAs。将要执行的代码包装到 这一点“在”一个AccessController::doPrivilegedWithCombiner调用中,也传递替换访问控制上下文


    1除了使用自定义域和您自己的组合器实现之外,还有一种看似更简单的替代方法,将SNAA转换为Principal,并使用标准SubjectDomainCombiner,将它们绑定到当前AccessControlContext的域(如上所述,或者简单地通过Subject::doAs)。这种方法是否会降低策略的效率主要取决于调用堆栈的深度(访问控制上下文包含多少不同的域)。最终,在编写策略时,您认为可以避免作为域合并器的一部分实现的缓存优化将对您产生影响,因此这本质上是您必须在那时做出的设计决策