欢迎来到深入探讨PicketLink系列的第二部分。如果您错过了第一部分,可以在这里找到:这里。在第一部分中,您还可以找到一些有用的资源链接,例如PicketLink文档、分发二进制文件、源代码等。

在本期中,我们将更深入地探讨PicketLink对分区(Partition)的支持。首先,让我们确定PicketLink中的分区究竟是什么,以及它们是如何使用的。

什么是分区?

简单来说,PicketLink中的分区用于将身份(如用户、组和角色)相互隔离。您可能会问,为什么要这样做呢?嗯,这种功能的一个常见用例是针对服务于多个客户/公司的应用程序,每个客户都有自己的独立用户账户集。另一个用例可能是当您希望将PicketLink用作IDP(身份提供者)来服务于多个应用程序时,每个应用程序都有自己的独立身份集。当您需要支持创建独立的“集合”的用户或其他身份类型时,分区可以帮助您。

我需要使用它们吗?

如果您的应用程序具有简单的安全要求,例如单一用户账户集以及可能的一些组和角色,那么您可能不需要使用PicketLink对分区的扩展支持。好消息是,您实际上不需要做任何特别的事情——只需忽略PicketLink的分区方面,它就不会打扰您!(如果您喜欢,也可以跳过本文的其余部分,稍后再来看第三部分)。

分区和身份模型

如果您阅读了第一部分,您可能还记得身份模型是如何描述的,以及每个身份对象是如何实现IdentityType接口,如图所示类图

我们在第一部分没有解释的是每个IdentityType对象必须属于一个分区。这意味着每个用户、组、角色、代理、账户(或任何其他身份类型)都有一个分区对象,并且它的getPartition()方法将始终返回此对象(绝不会null)。如果您已经使用过PicketLink API,您可能已经注意到PartitionManager接口上的这些重载方法PartitionManager接口

    IdentityManager createIdentityManager() throws IdentityManagementException;
    IdentityManager createIdentityManager(Partition partition) throws IdentityManagementException;

乍一看,这些方法中可能有一个会返回一个“无分区”的IdentityManager实例,然而在幕后,PicketLink实际上返回一个默认分区的IdentityManager。我们将在稍后更详细地探讨这个问题,但首先让我们看看PicketLink如何支持不同的分区类型。

创建自定义分区类型

由于分区接口本身不能实例化,通常由开发人员提供具体的分区实现。PicketLink提供两种内置分区类型,您可以使用它们(详细信息请见下一节),但除此之外,创建自己的分区类型非常简单。通过为我们完成大部分工作,AbstractPartition抽象基类使得创建自定义分区类型变得简单,并且可以轻松扩展以创建自定义分区类型。让我们看看一个非常简单的例子

@IdentityPartition(supportedTypes = {IdentityType.class})
public class Organization extends AbstractPartition {
    public Organization() {
        super(null);
    }
    public Organization(String name) {
        super(name);
    }
}

这就是我们需要的所有代码!我们可以使用这个新的Organization分区类型来创建不同组织内的身份。上面代码中唯一真正值得特别提及的显著特性是@IdentityPartition注解。这个注解告诉PicketLink这个类是一个分区类,并且允许存储所有类型(包括任何IdentityType子类IdentityType)。如果我们只想在分区中存储User对象,我们可以用以下方式注解类

@IdentityPartition(supportedTypes = {User.class})

还可能通过在unsupportedTypes成员中指定它们,从层次树中“裁剪”对某些身份类的支持。例如,假设我们希望能够在Organization中存储所有身份类型,除了角色。注解现在将如下所示

@IdentityPartition(supportedTypes = {IdentityType.class}, unsupportedTypes = {Role.class})

最后,由于分区接口扩展了AttributedType,我们知道它将有一个唯一的标识符,并且我们还可以分配任意的属性值,因此,我们可以使用我们的新Organization分区

Organization org = new Organization(acme);
org.setAttribute(new Attribute<String>(description, Manufactures anvils and other failure-prone devices);
partitionManager.add(org);
log.info(Created new Organization partition with id:  + org.getId());

执行类似这样的操作

内置分区类型PicketLink提供两种内置的可选分区类型 -RealmTier。这两个类都可以在org.picketlink.idm.model.basic

PicketLink提供两种内置的可选分区类型 -

包中找到,以及其他构成基本身份模型的类。这两种分区类型仅出于方便提供,绝对没有要求您使用其中任何一个。如果您希望使用这些内置分区类型,那么以下是我们的一些指南(您可以选择忽略)PicketLink提供两种内置的可选分区类型 -分区类型类似于通常接受的安全域的定义,建议在您需要为限制对应用程序的访问而创建一组独特的用户、组、角色(或任何其他身份类型)时使用。它支持所有身份类型。

A设计用于与PicketLink提供两种内置的可选分区类型 -一起使用,并且旨在仅存储角色或组(或任何其他非账户身份类型,即无法进行身份验证的身份类型,如UserPicketLink提供两种内置的可选分区类型 -存储用户。它旨在用于存储特定层级的标识符;例如,如果您的应用程序由多个层级组成,则每个层级可以定义自己的角色集,这些角色集可以进一步分配特定的特定层级的权限。这样,在单独的PicketLink提供两种内置的可选分区类型 -中,可以轻松地为用户提供一个或多个特定的角色,以便他们可以访问该层级提供的服务。

默认分区

如上所述,在由IdentityManager返回的PartitionManager.createIdentityManager()方法上执行的标识管理操作实际上是在默认分区中完成的。实际上,这个默认分区是一个名为“DEFAULT”的PicketLink提供两种内置的可选分区类型 -对象。如果您的PicketLink环境未配置为支持分区,则无需担心,PicketLink将透明地处理默认分区的支持,无需您进行任何特殊操作。

分区和关系

到目前为止,我们还没有提到身份关系在分区中的位置。从本质上讲,关系与身份不同,因为它们不属于特定的分区。如果您这样考虑,这很有意义,因为关系是两个或多个身份之间的类型化关联,而这些身份可能不属于同一分区。例如,根据上述PicketLink提供两种内置的可选分区类型 -Realm分区的描述,我们知道可以有一个Role存在于一个,通过一个Grant关系授予给一个UserPicketLink提供两种内置的可选分区类型 -.

之外的范围,本文不会详细介绍PicketLink如何确定关系状态的存储位置,但这可能是一个未来深入研究的好主题。

分区和多个配置

PicketLink允许同时声明多个配置,每个配置都有一个独特的名称。单个配置可以配置一个或多个身份存储来存储身份状态。通过支持多个配置,PicketLink可以控制用于存储每个分区的身份状态的底层身份存储。这听起来可能有点复杂,所以让我们用一个描述虚构的纸张公司的可能用例的图表来说明

在这个例子中,我们的纸张公司有两个配置,“公共”和“内部”。“公共”配置已被配置为使用基于JPA的身份存储,该存储使用数据库存储其身份状态。“内部”配置使用基于LDAP的身份存储,该存储由企业LDAP目录支持。除了这两个配置之外,我们还有两个领域分区——“用户”和“员工”。

让我们还假设我们的纸张公司运营一个电子商务网站,任何人都可以登录并为其产品下订单。公共用户的登录页面可能看起来像这样

通过这个登录表单(可以通过网站主页上的“登录”链接轻松找到)登录时,将使用“用户”领域执行身份验证。该网站还可能提供一个员工门户来管理订单和执行其他后台任务。希望访问此门户的员工将使用不同的网址(或可能是一个完全不同的应用程序,甚至可能仅在公司的私人网络上可用)并使用由“仅员工”登录表单支持的“员工”领域进行身份验证。我们可以使用以下图表表示不同的登录页面及其相关的领域

应用程序可以通过多种方式来支持这种多方面应用;它可以被构建为多个独立的层级,每个层级提供一组有限的函数(可能作为单独的应用或服务实现)以及一组特定的层级角色来控制如何分配访问这些函数的权限;它也可以被构建为一个单一的整体应用,所谓“万能”的应用(™),根据当前用户的访问级别限制对某些区域的访问。在任一情况下,都可以轻松地将全局权限分配给来自任一域的个别用户。例如,如果权限的形式是角色或组成员资格,则该角色或组可以存在于一个域中,而分配给它的用户可以存在于另一个域中。

例如,假设我们公司门户网站的“管理员”角色在“用户”域中定义,并且需要访问该网站的“审查订单”页面

正如我们所见,由于关系本身的性质是“跨分区”的,因此可以用来在不同域之间分配权限,所以这个角色分配给的用户存在于不同的域中并不重要。

分区管理API

PicketLink提供了一个简单的PartitionManagerAPI来管理分区。它可以很容易地注入到您的应用中,如下所示

import org.picketlink.idm.PartitionManager;
import javax.inject.Inject;

public class AdminService {
    @Inject PartitionManager partitionManager;
}

一旦您有了PartitionManager实例,您可以这样检索现有的分区或者您可以检索特定类型的所有分区

    Realm default = partitionManager.<Realm>getPartition(Realm.class, default);

创建一个新的

    List<Realm> realms = partitionManager.<Realm>getPartitions(Realm.class);

也很简单分区删除一个

    Tier orderServices = new Tier(orderServices);
    partitionManager.add(orderServices);

要在分区:

    Realm tempUsers = partitionManager.<Realm>getPartition(Realm.class, temp);
    partitionManager.remove(tempUsers);

内创建用户和其他身份对象,获取其分区的引用IdentityManager通过createIdentityManager()方法

    Realm default = partitionManager.<Realm>getPartition(Realm.class, default);
    IdentityManager im = partitionManager.createIdentityManager(default);

    User jsmith = new User(jsmith);
    im.add(jsmith);

要授予分区的引用内的用户权限,使用通过createPermissionManager()方法

    Realm default = partitionManager.<Realm>getPartition(Realm.class, default);
    User jsmith = new User(jsmith);
    im.add(jsmith);

    PermissionManager pm = partitionManager.createPermissionManager(default);
    pm.grantPermission(jsmith, Order.class, CREATE);

创建关系,获取无分区的RelationshipManager通过createRelationshipManager():

    RelationshipManager rm = partitionManager.createRelationshipManager();

一旦您有了RelationshipManager的引用,您可以使用它创建关系,如下所示,无论是同一分区内的身份之间,还是不同分区的关系之间

    Realm default = partitionManager.<Realm>getPartition(Realm.class, default);
    IdentityManager im = partitionManager.createIdentityManager(default);
    User jsmith = new User(jsmith);
    im.add(jsmith);
    Role admin = new Role(admin);
    im.add(admin);

    rm.add(new Grant(jsmith, admin));

或者在不同分区的关系之间

    Realm default = partitionManager.<Realm>getPartition(Realm.class, default);
    IdentityManager im = partitionManager.createIdentityManager(default);
    User jsmith = new User(jsmith);
    im.add(jsmith);

    Tier serviceTier = partitionManager.<Tier>getPartition(Tier.class, service);
    IdentityManager tim = partitionManager.createIdentityManager(serviceTier);
    Role admin = new Role(admin);
    tim.add(admin);

    rm.add(new Grant(jsmith, admin));

总结

PicketLink对分区的先进支持使我们能够创建适用于简单、单用途应用以及复杂、多层级企业平台的安全架构。在本文中,我们探讨了如何使用分区来创建不同的身份集合,并探讨了如何使用分区管理器API来管理分区。

再次感谢您的阅读!


返回顶部