跳到主要内容

为你的 Hasura 应用添加认证 (Authentication)

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

通常,Hasura 用户会使用其他身份管理和认证 (Authentication) 服务,其中 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 scope)和 user:maintainer(包含 maintain:user scope),以一对一对应 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. 自定义用户访问令牌 (Access token) 的额外声明 (Claims)

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

User access token script

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

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

5. 集成 Logto SDK

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

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',
],
};

获取用户访问令牌 (Access token) 并请求 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 请求时向 Logto 发送一个 Webhook 并等待响应;而基于 JWT 的方法可以持续使用,直到 JWT 过期。

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

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