受保护的应用程序
受保护的应用程序旨在通过将认证 (Authentication)层与应用程序分离,消除SDK 集成的复杂性。我们处理认证 (Authentication),让你专注于核心功能。一旦用户通过认证 (Authentication),受保护的应用程序将从你的服务器提供内容。
受保护的应用程序如何工作
受保护的应用程序由 Cloudflare 提供支持,在全球边缘网络上运行,确保你的应用程序具有低延迟和高可用性。
受保护的应用程序维护会话状态和用户信息。如果用户未通过认证 (Authentication),受保护的应用程序会将他们重定向到登录页面。一旦通过认证 (Authentication),受保护的应用程序将用户的请求与认证 (Authentication) 和用户信息一起包装,然后转发到源服务器。
此过程在以下流程图中可视化:
保护你的源服务器
源服务器可以是 Logto 的受保护应用程序不拥有的物理或虚拟设备,是你的应用程序内容所在的位置。类似于内容分发网络 (CDN) 服务器,受保护的应用程序管理认证 (Authentication) 过程并从你的源服务器检索内容。因此,如果用户直接访问你的源服务器,他们可以绕过认证 (Authentication),你的应用程序将不再受保护。
因此,保护源连接非常重要,它可以防止攻击者在未经认证 (Authentication) 的情况下发现和访问你的源服务器。有几种方法可以做到这一点:
- HTTP 头验证
- JSON Web Tokens (JWT) 验证
HTTP 头验证
可以使用 HTTP 基本认证 (Authentication) 来保护你的源服务器。
每个来自受保护应用程序的请求都包含以下头:
Authorization: Basic base64(appId:appSecret)
通过验证此头,你可以确认请求来自受保护的应用程序,并拒绝任何不包含此头的请求。
如果你使用 Nginx 或 Apache,可以参考以下指南在源服务器上实现 HTTP 基本认证 (Authentication):
要在应用程序中检查头,请参考 Cloudflare 提供的 HTTP 基本认证 (Authentication) 示例以了解如何使用 HTTP 基本模式限制访问。
JSON Web Tokens (JWT) 验证
另一种保护源服务器的方法是使用 JSON Web Tokens (JWT)。
每个来自受保护应用程序的认证 (Authentication) 请求都包含以下头:
Logto-ID-Token: <JWT>
JWT 称为 ID 令牌 (ID Token),由 Logto 签名并包含用户信息。通过验证此 JWT,你可以确认请求来自受保护的应用程序,并拒绝任何不包含此头的请求。
令牌被加密并签名为 JWS 令牌。
验证步骤:
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);
获取原始主机
如果你需要获取客户端请求的原始主机,可以使用 Logto-Host
或 x-forwarded-host
头。
自定义认证 (Authentication) 规则
默认情况下,受保护的应用程序将保护所有路由。如果你需要自定义认证 (Authentication) 规则,可以在控制台中设置“自定义认证 (Authentication) 规则”字段。
它支持正则表达式,这里有两个案例场景:
- 仅保护
/admin
和/privacy
路由:^/(admin|privacy)/.*
- 排除 JPG 图像的认证 (Authentication):
^(?!.*\.jpg$).*$
本地开发
受保护的应用程序旨在与源服务器一起工作。然而,如果你的源服务器无法公开访问,可以使用 ngrok 或 Cloudflare Tunnels 等工具将本地服务器暴露到互联网。
过渡到 SDK 集成
受保护的应用程序旨在简化认证 (Authentication) 过程。然而,如果你决定过渡到 SDK 集成以获得更好的控制和自定义,可以在 Logto 中创建一个新应用程序并配置 SDK 集成。为了顺利过渡,你可以重用受保护应用程序的应用程序配置。受保护的应用程序实际上是 Logto 中的“传统 Web 应用程序”,你可以在应用程序设置中找到“AppId”和“AppSecret”。过渡完成后,你可以从应用程序中移除受保护的应用程序。