跳到主要内容

为你的 Hasura 应用程序添加认证

Hasura 是一个可以快速为你的数据提供相应 GraphQL 和 REST API 的工具。考虑到数据安全,Hasura 还提供了为每个不同 API 进行细粒度访问控制的能力。

通常,Hasura 用户会使用其他身份管理和认证服务,其中 Logto 是一个非常受欢迎的选择。

在这篇博客文章中,我们将假设你已经在使用 Hasura 服务。我们将介绍如何集成 Hasura 和 Logto,以最大化你的数据安全性。如果你还没有 Logto 账户,立即注册并开始使用吧!

背景

Hasura 使用 基于角色的访问管理,而 Logto 使用标准的 基于角色的访问控制 (RBAC)

在 Logto 的模型和 RBAC 的最佳实践中,我们建议用户使用 权限 (scope) 来对应权限的最细粒度,使用 角色 (role) 作为一组 权限 (scope) 以便于批量操作,最终检查 权限 (scope)(通常在资源提供者一侧)以验证用户是否可以执行特定操作。

在 Hasura 中,角色 (role) 对应于权限的最细粒度,权限检查是针对 角色 (role) 进行的。因此,在配置 Logto 时,我们建议将一个 角色 (role) 映射到一个 权限 (scope)。这种方法可以将 Logto 和 Hasura 的权限连接在一起,以避免混淆和误用。

Hasura 可以通过 Webhook 或 JWT 支持访问控制。我们之前的 博客文章 介绍了如何使用 Webhook,接下来的部分中,我们将解释如何利用 Hasura 的 JWT 模式进行访问控制。

开始

让我们从一个简单的例子开始。假设用户已经在 Hasura 中有两个 API,GET /userPATCH /user,分别对应两个角色:user:readeruser:maintainer

1. 在 Logto 中创建 Hasura API 资源

在 Logto 中创建一个 Hasura API 资源。

Hasura API

2. 根据 Hasura 设置在 Logto 中创建角色

我们需要为步骤 1 中提到的 Hasura API 资源创建两个 权限 (scope),即 read:usermaintain:user,然后创建两个角色:user:reader(包含 read:user 权限)和 user:maintainer(包含 maintain:user 权限),以一对一对应 Hasura 的角色。并根据需要将这些角色分配给 Logto 用户。

Hasura API with scopes

User reader role

User maintainer role

3. 配置 Hasura 环境变量 HASURA_GRAPHQL_JWT_SECRET 以启用 JWT 模式

通过查看 Hasura JWT 配置选项,我们需要添加并配置环境变量 HASURA_GRAPHQL_JWT_SECRET,才能使用 JWT 进行访问控制。

有许多不同的选项可以配置,但这里我们介绍最简单的情况:只需要配置 jwk_url。这个值可以从你的 Logto 的 OpenID 配置端点 (https://your.logto.domain/oidc/.well-known/openid-configuration) 获取。

Hasura JWT config

4. 自定义用户访问令牌额外声明

使用 Logto 的自定义令牌声明功能,自定义逻辑以向用户访问令牌添加额外声明。

User access token script

自定义 getCustomJwtClaims 方法,以在 JWT 中添加 Hasura 依赖于实现访问控制的数据。这可以包括在该实例中被授权的用户相关数据,包括他们拥有的 角色 (role),可以通过 context 访问。

我们还定义了一个环境变量 USER_DEFAULT_ROLE_NAMES 以避免硬编码。

5. 集成 Logto SDK

在配置 Logto 和 Hasura 之后,将你的应用程序与 Logto SDK 集成。这里我们使用一个 React 示例来预览用户登录后 Logto 发放的用户访问令牌。

User with roles

首先,我们将之前创建的 user:readeruser:maintainer 角色分配给用户,然后以该用户身份登录。

const config: LogtoConfig = {
endpoint: 'http://localhost:3001',
appId: '<your-application-id>',
appSecret: '<your-application-secret>',
scopes: [
...// existing scopes
'read:user',
'maintain:user',
],
resources: [
...// existing resources
'https://*.hasura.app/api',
],
};

获取用户访问令牌并请求 Hasura API:

const accessToken = await logto.getAccessToken('https://*.hasura.app/api');

// 在发送请求到 Hasura 之前
request.headers.set('Authorization', `Bearer ${accessToken}`);
request.headers.set('x-Hasura-Role', '<required-role-for-the-endpoint>');

结论

在本文中,我们提供了 Hasura 支持的另一种基于 JWT 的访问控制方法,除了 Webhook。

通过比较 Hasura 的 WebhookJWT 访问控制的过程,我们可以看到 Webhook 方法在每个 Hasura 请求时都会发送一个 Webhook 到 Logto 并等待响应;而基于 JWT 的方法可以持续使用,直到 JWT 过期。

JWT 方法可以减少网络负载,并消除 Webhook 带来的网络延迟;同时,Webhook 方法可以实时同步用户权限的变化。

用户可以根据这些结论,结合他们的实际业务需求,选择合适的方法。