Skip to main content

编写许可政策

上一节因此,我们能够设置权限框架,并对我们的TestPermissionPolicy以确认策略的连接是否正确。

这项政策是这样的

packages/backend/src/plugins/permission.ts
class TestPermissionPolicy implements PermissionPolicy {
async handle(request: PolicyQuery): Promise<PolicyDecision> {
if (request.permission.name === 'catalog.entity.delete') {
return {
result: AuthorizeResult.DENY,
};
}

return { result: AuthorizeResult.ALLOW };
}
}

政策中有哪些内容?

让我们进一步细分一下。政策查询是对权限对象该权限对象封装了有关用户试图执行的操作的信息(参见概念页面了解更多详情)。

在上面的策略中,我们会检查所提供的操作是否是目录实体删除操作,这是目录插件作者创建的权限,用于表示取消注册目录实体的操作。 如果是,我们会返回一个确定性政策决定在所有其他情况下,我们都返回 ALLOW(默认允许行为)。

正如我们在上一节中确认的那样,我们知道这可以阻止我们取消注册目录组件。 万岁!但是你可能会注意到,这阻止了任何人的组件取消注册,这不是一个非常现实的策略。 让我们通过禁用取消注册操作来改进这一策略除非您是该组件的 Owner_。.

有条件的决定

让我们将政策改为以下内容:

import { IdentityClient } from '@backstage/plugin-auth-node';
import {
BackstageIdentityResponse,
IdentityClient
} from '@backstage/plugin-auth-node';
import {
AuthorizeResult,
PolicyDecision,
isPermission,
} from '@backstage/plugin-permission-common';
import {
catalogConditions,
createCatalogConditionalDecision,
} from '@backstage/plugin-catalog-backend/alpha';
import {
catalogEntityDeletePermission,
} from '@backstage/plugin-catalog-common/alpha';

class TestPermissionPolicy implements PermissionPolicy {
async handle(request: PolicyQuery): Promise<PolicyDecision> {
async handle(
request: PolicyQuery,
user?: BackstageIdentityResponse,
): Promise<PolicyDecision> {
if (request.permission.name === 'catalog.entity.delete') {
if (isPermission(request.permission, catalogEntityDeletePermission)) {
return {
result: AuthorizeResult.DENY,
};
return createCatalogConditionalDecision(
request.permission,
catalogConditions.isEntityOwner({
claims: user?.identity.ownershipEntityRefs ?? [],
}),
);
}
return { result: AuthorizeResult.ALLOW };
}
}

让我们来看看刚刚添加的新代码。

我们不返回 "确定性决策",而是使用工厂方法来构建一个有条件的决策概念页面由于该策略没有足够的信息来判断是否user但是,如果 Oner 是实体的所有者,则这一标准被封装在条件决定中、createCatalogConditionalDecision将无法编译,除非request.permission是目录实体资源权限这种类型约束确保策略返回的条件决定与请求的权限相匹配。 为了解决这个问题,我们使用isPermission"窄"的类型request.permissionResourcePermission<'catalog-entity'>这与之前的运行时行为一致,但你会发现request.permission的范围内发生了变化if声明。

catalogConditions对象包含目录插件定义的所有规则。 这些规则可以组合成一个权限标准对象,但在这种情况下,我们只需要使用isEntityOwner该规则接受一个实体引用列表,这些实体引用代表用于确定所有权的用户身份和组员身份。PermissionPolicy#handle为我们提供了BackstageIdentityResponse对象,从中获取用户的ownershipEntityRefs由于用户可能是匿名的,我们提供了一个空数组作为备用。

现在你应该可以在Backstage应用程序中看到,取消注册实体按钮对你拥有的实体是启用的,但对所有其他实体是禁用的!

资源类型

现在,假设我们想阻止对目录实体的所有操作,除非这些操作是由 Owner 执行的。 实现这一点的方法之一可能是简单地更新if如果你选择以这种方式编写策略,肯定行得通!不过,随着策略的增加,维护起来可能会很困难,而且如果遗漏了某些权限,可能并不明显。 我们可以通过检查所请求权限的资源类型,以更具可扩展性的方式编写相同的策略。

import {
AuthorizeResult,
PolicyDecision,
isPermission,
isResourcePermission,
} from '@backstage/plugin-permission-common';
import {
catalogConditions,
createCatalogConditionalDecision,
} from '@backstage/plugin-catalog-backend/alpha';
import {
catalogEntityDeletePermission,
} from '@backstage/plugin-catalog-common/alpha';

class TestPermissionPolicy implements PermissionPolicy {
async handle(
request: PolicyQuery,
user?: BackstageIdentityResponse,
): Promise<PolicyDecision> {
if (isPermission(request.permission, catalogEntityDeletePermission)) {
if (isResourcePermission(request.permission, 'catalog-entity')) {
return createCatalogConditionalDecision(
request.permission,
catalogConditions.isEntityOwner({
claims: user?.identity.ownershipEntityRefs ?? [],
}),
);
}

return { result: AuthorizeResult.ALLOW };
}
}

在本例中,我们使用isResourcePermission以匹配所有资源类型为catalog-entity就像isPermission的类型,该助手将 "缩小 "该类型的request.permission并启用createCatalogConditionalDecision除了之前观察到的行为外,你还应该看到目录实体不再可见,除非你是 Owner - 成功!

注:_某些目录权限没有'catalog-entity'资源类型,如目录实体创建权限在这种情况下,需要做出明确的决定,因为条件不能适用于一个尚不存在的实体。