跳到主要内容

指南:Node (Express)

步骤 1:从请求头中提取 Bearer 令牌

一个授权请求应包含一个 Authorization 头,其内容为 Bearer <access_token>。从请求头中提取授权令牌 (Authorization token):

// auth_middleware.ts

import { IncomingHttpHeaders } from 'http';

const extractBearerTokenFromHeaders = ({ authorization }: IncomingHttpHeaders) => {
const bearerTokenIdentifier = 'Bearer';

if (!authorization) {
throw new Error({ code: 'auth.authorization_header_missing', status: 401 });
}

if (!authorization.startsWith(bearerTokenIdentifier)) {
throw new Error({ code: 'auth.authorization_token_type_not_supported', status: 401 });
}

return authorization.slice(bearerTokenIdentifier.length + 1);
};

步骤 2:令牌验证

为了演示,我们使用 jose 包来验证令牌的签名、过期状态和所需的声明 (Claims)。

安装 jose 作为你的依赖

npm i jose --save

获取 Logto 的 OIDC 配置

你将需要一个 JWK 公钥集和令牌发行者 (Issuer) 来验证接收到的 JWS 令牌的签名和来源。所有最新的 Logto 授权配置可以在 https://<your-logto-domain>/oidc/.well-known/openid-configuration 找到。

例如,调用 https://tenant-id.logto.app/oidc/.well-known/openid-configuration。并在响应体中找到以下两个字段:

{
"jwks_uri": "https://tenant-id.logto.app/oidc/jwks",
"issuer": "https://tenant-id.logto.app/oidc"
}

添加认证中间件

Jose 的 jwtVerify 方法可以帮助你验证令牌的 JWS 格式、令牌签名、发行者 (Issuer)、受众 (Audience) 和过期状态。如果验证失败,将抛出异常。

注意

如果你使用 基于角色的访问控制 (RBAC),还需要进行权限 (Scope) 验证。

// auth-middleware.ts

import { createRemoteJWKSet, jwtVerify } from 'jose';

//...

export const verifyAuthFromRequest = async (req, res, next) => {
// 提取令牌
const token = extractBearerTokenFromHeaders(req.headers);

const { payload } = await jwtVerify(
token, // 从请求头中提取的原始 Bearer 令牌
createRemoteJWKSet(new URL('https://<your-logto-domain>/oidc/jwks')), // 使用从 Logto 服务器查询的 jwks_uri 生成 jwks
{
// 令牌的预期发行者 (Issuer),应由 Logto 服务器发行
issuer: 'https://<your-logto-domain>/oidc',
// 预期的受众 (Audience) 令牌,应为当前 API 的资源指示器 (Resource indicator)
audience: '<your request listener resource indicator>',
}
);

// 如果你使用 RBAC
assert(payload.scope.includes('some_scope'));

// 自定义负载逻辑
userId = payload.sub;

return next();
};

将中间件应用于你的 API

import { verifyAuthFromRequest } from '/middleware/auth-middleware.ts';

app.get('/user/:id', verifyAuthFromRequest, (req, res, next) => {
// 自定义代码
});