Protected App — 非 SDK 认证 (Authentication) 集成
Protected App 旨在通过将认证 (Authentication)层与应用程序分离,消除SDK 集成的复杂性。我们负责认证 (Authentication),让你专注于核心功能。一旦用户通过认证 (Authentication),Protected App 就会从你的服务器提供内容。
Protected App 的工作原理
Protected App 由 Cloudflare 提供支持,在全球边缘网络上运行,确保你的应用低延迟和高可用性。
Protected App 会维护会话状态和用户信息。如果用户未通过认证 (Authentication),Protected App 会将其重定向到登录页面。认证 (Authentication) 成功后,Protected App 会将用户的请求附带认证 (Authentication) 和用户信息后转发到源服务器。
此过程可通过以下流程图进行可视化:
保护你的源服务器
源服务器可以是物理或虚拟设备,不属于 Logto 的 Protected App,存放你的应用内容。类似于内容分发网络 (CDN) 服务器,Protected App 管理认证 (Authentication) 流程并从你的源服务器获取内容。因此,如果用户可以直接访问你的源服务器,就能绕过认证 (Authentication),你的应用将不再受保护。
因此,保护源服务器连接非常重要,这可以防止攻击者在未认证 (Authentication) 的情况下发现并访问你的源服务器。常见的做法有:
- HTTP 头验证
- JSON Web Token (JWT) 验证
HTTP 头验证
你可以使用 HTTP 基本认证 (Authentication) 来保护你的源服务器。
每个来自 Protected App 的请求都会包含如下头部:
Authorization: Basic base64(appId:appSecret)
通过验证此头部,你可以确认请求来自 Protected App,并拒绝所有未包含此头部的请求。
如果你使用 Nginx 或 Apache,可以参考以下指南在源服务器上实现 HTTP 基本认证 (Authentication):
如需在应用程序中检查头部,请参考 Cloudflare 提供的 HTTP Basic Authentication 示例,了解如何使用 HTTP Basic 方案限制访问。
JSON Web Token (JWT) 验证
另一种保护源服务器的方法是使用 JSON Web Token (JWT)。
每个通过认证 (Authentication) 的 Protected App 请求都会包含如下头部:
Logto-ID-Token: <JWT>
该 JWT 被称为 ID 令牌 (ID token),由 Logto 签名并包含用户信息。通过验证此 JWT,你可以确认请求来自 Protected App,并拒绝所有未包含此头部的请求。
该令牌采用 JWS 令牌格式进行加密和签名。
验证步骤如下:
- 验证 JWT
- 验证 JWS 签名
- 令牌的发行者 (Issuer) 是
https://<your-logto-domain>/oidc(由你的 Logto 认证 (Authentication) 服务器签发)
const express = require('express');
const jwksClient = require('jwks-rsa');
const jwt = require('jsonwebtoken');
const ISSUER = 'https://<your-logto-domain>/oidc';
const CERTS_URL = 'https://<your-logto-domain>/oidc/jwks';
const client = jwksClient({
jwksUri: CERTS_URL,
});
const getKey = (header, callback) => {
client.getSigningKey(header.kid, function (err, key) {
callback(err, key?.getPublicKey());
});
};
const verifyToken = (req, res, next) => {
const token = req.headers['Logto-ID-Token'];
// 确保传入请求包含我们的令牌头部
if (!token) {
return res.status(403).send({ status: false, message: '缺少必需的 Logto-ID-Token 头部' });
}
jwt.verify(token, getKey, { issuer: ISSUER }, (err, decoded) => {
if (err) {
return res.status(403).send({ status: false, message: '无效的 ID 令牌' });
}
req.user = decoded;
next();
});
};
const app = express();
app.use(verifyToken);
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000);
获取认证 (Authentication) 状态和用户信息
如果你需要为应用获取认证 (Authentication) 和用户信息,也可以使用 Logto-ID-Token 头部。
如果你只想解码令牌,可以使用如下代码:
const express = require('express');
const decodeIdToken = (req, res, next) => {
const token = req.headers['Logto-ID-Token'];
if (!token) {
return res.status(403).send({
status: false,
message: '缺少必需的 Logto-ID-Token 头部',
});
}
const parts = token.split('.');
if (parts.length !== 3) {
throw new Error('无效的 ID 令牌');
}
const payload = parts[1];
const decodedPayload = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));
const claims = JSON.parse(decodedPayload);
req.user = claims;
next();
};
const app = express();
app.use(decodeIdToken);
app.get('/', (req, res) => {
res.json(req.user);
});
app.listen(3000);
自定义 ID 令牌 (ID token) 声明 (Claims)
默认情况下,Logto-ID-Token 头部包含标准 OIDC 声明 (Claims)(如 sub、name 和 email)。如需包含扩展声明 (Claims)(如角色或组织数据),需同时配置以下两项:
- 租户开关:在 控制台 > 自定义 JWT > ID 令牌 (ID token) 中启用该声明 (Claim)。
- Protected App 权限 (Scopes):在 Protected App 设置中,于 ID 令牌 (ID token) 声明 (Claims) > 附加权限 (Scopes) 选择对应权限 (Scope)。
仅当在自定义 JWT 中启用声明 (Claim) 且为 Protected App 选择了对应权限 (Scope) 时,扩展声明 (Claims) 才会包含在转发的 ID 令牌 (ID token) 中。完整扩展权限 (Scopes) 和声明 (Claims) 列表见 自定义 ID 令牌 (ID token)。
| 权限 (Scope) | 声明 (Claims) |
|---|---|
custom_data | custom_data |
identities | identities, sso_identities |
roles | roles |
urn:logto:scope:organizations | organizations, organization_data |
urn:logto:scope:organization_roles | organization_roles |
获取原始主机
如果你需要获取客户端请求的原始主机,可以使用 Logto-Host 或 x-forwarded-host 头部。
自定义认证 (Authentication) 规则
默认情况下,Protected App 会保护所有路由。如果你需要自定义认证 (Authentication) 规则,可以在控制台设置“自定义认证 (Authentication) 规则”字段。
支持正则表达式,以下是两种场景示例:
- 仅保护
/admin和/privacy路由:^/(admin|privacy)/.* - 排除 JPG 图片不进行认证 (Authentication):
^(?!.*\.jpg$).*$
本地开发
Protected App 设计用于与你的源服务器配合使用。如果你的源服务器无法公开访问,可以使用 ngrok 或 Cloudflare Tunnels 等工具将本地服务器暴露到互联网。
迁移到 SDK 集成
Protected App 旨在简化认证 (Authentication) 流程。但如果你希望获得更好的控制和自定义,可以选择迁移到 SDK 集成。你可以在 Logto 中创建新应用并配置SDK 集成。为顺利迁移,你可以复用 Protected App 的应用配置。Protected App 实际上是 Logto 中的“传统 Web 应用”,你可以在应用设置中找到 “AppId” 和 “AppSecret”。迁移完成后,可以将 Protected App 从你的应用中移除。
相关资源
Protected App:几步构建你的应用认证 (Authentication),无需代码。
Protected App 背后的动机构建认证 (Authentication) 系统的最快方式