Auth Guard 模块
Auth Guard 模块允许您在用户登录流程中实施额外的身份验证和授权检查。 该模块在标准身份验证(密码、MFA、设备验证)之后、授予访问权限之前执行,非常适合强制执行合规策略(例如法律协议、安全检查)、添加自定义多因素授权或验证 mTLS 证书。
{ "modules": { "auth-guard": [ { "key": "your-module-key", "name": "IP Whitelist Check", "description": "Verifies user IP address", "url": "/api/auth/verify", "options": { "type": "direct", "applyToAdmins": false } } ] }}key | 类型: 必填: 是 描述: Crowdin 应用内的模块标识符。 |
name | 类型: 必填: 是 描述: 验证期间向用户显示的可读名称。 |
description | 类型: 必填: 否 描述: 向用户显示的附加描述。 仅适用于 |
url | 类型: 必填: 是 描述: 用于验证的端点 URL。 相对于 |
options | 类型: 必填: 否 描述: 模块配置选项。 |
options.type | 类型: 允许值: 默认值: 描述: 验证交互类型。 |
options.applyToAdmins | 类型: 默认值: 描述: 是否对组织管理员应用此检查。 |
options.url | 类型: 必填: 是(如果类型为 描述: 用于交互的面向用户的 URL。 |
Auth Guard 模块在身份验证过程中充当安全检查点。 它在标准验证步骤(密码、MFA、设备信任)之后、向用户授予组织访问权限之前调用。
根据配置,该模块可以通过以下三种方式之一与用户交互:
下图说明了 Auth Guard 模块在用户登录流程中的位置:
用户登录 ↓密码验证 ↓MFA 验证(如已启用) ↓设备信任验证(如已启用) ↓┌─────────────────────────┐│ Auth Guard 模块 │ ← 您的应用└─────────────────────────┘ ↓记住我确认(如已启用) ↓授予访问权限每个组织可以配置多个 Auth Guard 模块。 它们按顺序执行,所有模块都必须通过,用户才能获得访问权限。
直接类型是最简单的交互方式,非常适合不需要用户输入的自动化检查(例如证书验证)。 Crowdin 向您的应用发起同步服务器到服务器 API 调用,应用必须立即响应(< 10 秒)。
┌─────────────┐ ┌──────────────┐│ Crowdin │ │ 您的应用 │└──────┬──────┘ └──────┬───────┘ │ │ │ POST /api/auth/verify │ │ Authorization: Bearer <JWT> │ │ { │ │ "userId": 12345, │ │ "organizationId": 67890, │ │ "ipAddress": "192.168.1.1", │ │ "moduleKey": "your-module-key" │ │ } │ ├─────────────────────────────────────────────────>│ │ │ │ 处理验证 │ │ (IP 检查等) │ │ │ │ { "success": true } │ │ 或 │ │ { │ │ "success": false, │ │ "message": "Access denied: IP not allowed" │ │ } │ │<─────────────────────────────────────────────────┤ │ │HTTP 请求:
POST {AppBaseUrl}/api/auth/verify请求头
向您的应用发出的请求将包含以下请求头:
Authorization: Bearer \<JWT_TOKEN>Content-Type: application/json
请求载荷示例:
{ "userId": 12345, "organizationId": 67890, "ipAddress": "192.168.1.1", "moduleKey": "your-module-key"}应用必须返回一个 JSON 对象,指示成功或失败。
响应载荷示例(成功):
{ "success": true}响应载荷示例(失败):
{ "success": false, "message": "Access denied: Your IP address is not in the allowlist"}重定向类型将用户路由到外部页面进行验证,然后将其重定向回 Crowdin。 当需要用户交互时(例如接受条款、解决 CAPTCHA 或与外部 OAuth/SAML 提供商集成),此类型非常适用。
┌─────────┐ ┌──────────────┐ ┌──────────┐│ 用户 │ │ Crowdin │ │ 您的应用 │└────┬────┘ └──────┬───────┘ └────┬─────┘ │ │ │ │ 1. 登录尝试 │ │ ├───────────────────────────────────>│ │ │ │ │ │ │ Try POST /api/auth/verify │ │ │ (with empty body initially) │ │ ├─────────────────────────────────>│ │ │ │ │ │ { "success": false } │ │ │ (needs user interaction) │ │ │<─────────────────────────────────┤ │ │ │ │ 2. HTTP 302 重定向 │ │ │ Location: https://your-app/page │ │ │ ?jwtToken=<JWT>&state=<STATE> │ │ │<───────────────────────────────────┤ │ │ │ │ │ 3. GET /page?jwtToken=...&state=... │ ├──────────────────────────────────────────────────────────────────────>│ │ │ │ │ │ 验证 JWT 令牌 │ │ │ 显示验证界面 │ │ │ │ │ 4. 显示验证页面 │ │<──────────────────────────────────────────────────────────────────────┤ │ │ │ │ 5. 用户完成验证 │ │ (点击批准/拒绝) │ │ ├──────────────────────────────────────────────────────────────────────>│ │ │ │ │ │ 生成验证码 │ │ │ │ │ 6. HTTP 302 重定向返回 │ │ Location: https://accounts.../callback │ │ ?state=<STATE>&code=<CODE> │ │ │ or ...?state=<STATE>&error=... │ │ │<──────────────────────────────────────────────────────────────────────┤ │ │ │ │ 7. GET /callback?state=...&code=... │ ├───────────────────────────────────>│ │ │ │ │ │ │ POST /api/auth/verify │ │ │ { │ │ │ "code": "<CODE>", │ │ │ "userId": ..., │ │ │ "organizationId": ..., │ │ │ "ipAddress": ..., │ │ │ "moduleKey": "..." │ │ │ } │ │ ├─────────────────────────────────>│ │ │ │ │ │ { "success": true } │ │ │<─────────────────────────────────┤ │ │ │ │ 8. 授予访问权限 │ │ │<───────────────────────────────────┤ │ │ │ │Crowdin 首先尝试直接检查,以确认是否可以自动授予访问权限。
HTTP 请求:
POST {AppBaseUrl}/api/auth/verify请求头
向您的应用发出的请求将包含以下请求头:
Authorization: Bearer \<JWT_TOKEN>Content-Type: application/json
请求载荷示例:
{ "userId": 12345, "organizationId": 67890, "ipAddress": "192.168.1.1", "moduleKey": "your-module-key"}预期响应(触发重定向):
要触发重定向流程,您的应用必须返回 success: false。
{ "success": false}如果初始检查返回 false,Crowdin 会将用户重定向到清单选项中 url 定义的地址。
重定向 URL 结构:
https://{your-app-url}?jwtToken=<JWT>&state=<STATE>您的应用必须验证 jwtToken,显示验证 UI,并在成功后使用 HTTP 302 重定向将用户重定向回 Crowdin。
成功时:
HTTP 302 RedirectLocation: https://accounts.crowdin.com/{domain}/guard/callback?state=<STATE>&code=<CODE>失败时:
HTTP 302 RedirectLocation: https://accounts.crowdin.com/{domain}/guard/callback?state=<STATE>&error=User+denied+access一旦 Crowdin 从回调中收到 code,它将向您的应用发送最终请求以进行验证。
HTTP 请求:
POST {AppBaseUrl}/api/auth/verify请求头
Authorization: Bearer \<JWT_TOKEN>Content-Type: application/json
请求载荷示例:
{ "code": "abc123xyz", "userId": 12345, "organizationId": 67890, "ipAddress": "192.168.1.1", "moduleKey": "your-module-key"}预期响应:
{ "success": true}Frame 类型在 Crowdin 登录界面内的 iframe 中显示您的验证页面。 这为自定义表单或 mTLS 检查提供了无缝的用户体验,同时将用户保留在 Crowdin 环境中。
┌─────────┐ ┌──────────────┐ ┌──────────┐│ 用户 │ │ Crowdin │ │ 您的应用 │└────┬────┘ └──────┬───────┘ └────┬─────┘ │ │ │ │ 1. 登录尝试 │ │ ├───────────────────────────────>│ │ │ │ │ │ │ Try POST /api/auth/verify │ │ ├─────────────────────────────────>│ │ │ │ │ │ { "success": false } │ │ │<─────────────────────────────────┤ │ │ │ │ 2. 显示验证页面 │ │ │ 含嵌入 iframe │ │ │<───────────────────────────────┤ │ │ │ │ │ 3. Iframe 加载您的 URL │ │ │ GET /frame?jwtToken=... │ │ ├──────────────────────────────────────────────────────────────────>│ │ │ │ │ 4. 您的验证界面 │ │ │<──────────────────────────────────────────────────────────────────┤ │ │ │ │ 5. 用户与 iframe 交互 │ │ │ (点击批准/拒绝) │ │ │────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ 6. 通过以下方式调用 JS API │ │ │ │ Crowdin Apps SDK │ │ │ │ AP.verifyAuth({ code: "..."}) │ │ ├────────────────────────────────────────────────────────────────┼─>│ │ │ │ │ │ 7. Crowdin 通过 postMessage │<──────────────────────────────┘ │ │ 从 iframe 接收验证码 │ │ │ │ │ │ │ POST /api/auth/verify │ │ │ { │ │ │ "code": "...", │ │ │ "userId": ..., │ │ │ "moduleKey": "..." │ │ │ } │ │ ├─────────────────────────────────>│ │ │ │ │ │ { "success": true } │ │ │<─────────────────────────────────┤ │ │ │ │ 8. 授予访问权限 │ │ │<───────────────────────────────┤ │ │ │ │Crowdin 首先尝试直接检查,以确认是否可以自动授予访问权限。
HTTP 请求:
POST {AppBaseUrl}/api/auth/verify请求载荷示例:
{ "userId": 12345, "organizationId": 67890, "ipAddress": "192.168.1.1", "moduleKey": "your-module-key"}预期响应(触发 Iframe):
要触发 iframe 流程,您的应用必须返回 success: false。
{ "success": false}如果初始检查返回 false,Crowdin 将使用以下参数在 iframe 中加载您应用的 url:
https://{your-app-url}?jwtToken=<JWT>验证 UI 实现:
创建一个 HTML 页面,初始化 Crowdin Apps SDK 并处理用户交互。
<!DOCTYPE html><html> <head> <title>Verification</title>
<script src="https://cdn.crowdin.com/apps/dist/host.js"></script> </head> <body> <h1>Security Verification</h1> <p>Please confirm your identity</p>
<button id="approve">Approve</button> <button id="deny">Deny</button>
<script> // Get parameters const urlParams = new URLSearchParams(window.location.search); const jwtToken = urlParams.get('jwtToken'); const state = urlParams.get('state');
document.getElementById('approve').addEventListener('click', async () => { // Generate verification code from your backend const code = await generateVerificationCode();
// Send success to Crowdin via SDK AP.verifyAuth({ code: code }); });
document.getElementById('deny').addEventListener('click', () => { // Send rejection to Crowdin AP.verifyAuth({ error: 'User denied access' }); });
async function generateVerificationCode() { // Call your backend to generate a code const response = await fetch('/api/generate-code', { method: 'POST', headers: { 'Authorization': `Bearer ${jwtToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ state }) }); const data = await response.json(); return data.code; } </script> </body></html>使用 AP.verifyAuth() 方法将结果传回 Crowdin。
成功:
AP.verifyAuth({ code: "your-verification-code"});失败:
AP.verifyAuth({ error: "Verification failed: device not trusted"});一旦 Crowdin 从 SDK 收到 code,它将向您的应用发送最终请求以进行验证。
HTTP 请求:
POST {AppBaseUrl}/api/auth/verify请求载荷示例:
{ "code": "abc123xyz", "userId": 12345, "organizationId": 67890, "ipAddress": "192.168.1.1", "moduleKey": "your-module-key"}预期响应:
{ "success": true}