继身份认证与授权(一):SAML、OIDC之后,本文继续深入汇总介绍几个商业平台。
Okta
官网,全球领先的企业级IAM解决方案提供商,专注于为企业提供云端的身份验证、单点登录、多因素认证(MFA)、用户管理等服务。
核心产品线:
- Okta Workforce Identity(员工身份管理):
- 单点登录到企业应用
- MFA
- 生命周期管理(用户入职/离职自动化)
- 高级服务器访问(ASA),替代VPN的服务器访问方案
- Okta Customer Identity(客户身份管理,原Okta CIAM):
- 面向外部用户的身份认证
- 支持数百万用户规模
- 自定义登录页面和品牌化
- 社交登录和企业联合认证
架构:
#mermaid-svg-KnDQYUzEEOijtRL1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KnDQYUzEEOijtRL1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KnDQYUzEEOijtRL1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KnDQYUzEEOijtRL1 .error-icon{fill:#552222;}#mermaid-svg-KnDQYUzEEOijtRL1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KnDQYUzEEOijtRL1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KnDQYUzEEOijtRL1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KnDQYUzEEOijtRL1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KnDQYUzEEOijtRL1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KnDQYUzEEOijtRL1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KnDQYUzEEOijtRL1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KnDQYUzEEOijtRL1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KnDQYUzEEOijtRL1 .marker.cross{stroke:#333333;}#mermaid-svg-KnDQYUzEEOijtRL1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KnDQYUzEEOijtRL1 p{margin:0;}#mermaid-svg-KnDQYUzEEOijtRL1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KnDQYUzEEOijtRL1 .cluster-label text{fill:#333;}#mermaid-svg-KnDQYUzEEOijtRL1 .cluster-label span{color:#333;}#mermaid-svg-KnDQYUzEEOijtRL1 .cluster-label span p{background-color:transparent;}#mermaid-svg-KnDQYUzEEOijtRL1 .label text,#mermaid-svg-KnDQYUzEEOijtRL1 span{fill:#333;color:#333;}#mermaid-svg-KnDQYUzEEOijtRL1 .node rect,#mermaid-svg-KnDQYUzEEOijtRL1 .node circle,#mermaid-svg-KnDQYUzEEOijtRL1 .node ellipse,#mermaid-svg-KnDQYUzEEOijtRL1 .node polygon,#mermaid-svg-KnDQYUzEEOijtRL1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KnDQYUzEEOijtRL1 .rough-node .label text,#mermaid-svg-KnDQYUzEEOijtRL1 .node .label text,#mermaid-svg-KnDQYUzEEOijtRL1 .image-shape .label,#mermaid-svg-KnDQYUzEEOijtRL1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-KnDQYUzEEOijtRL1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KnDQYUzEEOijtRL1 .rough-node .label,#mermaid-svg-KnDQYUzEEOijtRL1 .node .label,#mermaid-svg-KnDQYUzEEOijtRL1 .image-shape .label,#mermaid-svg-KnDQYUzEEOijtRL1 .icon-shape .label{text-align:center;}#mermaid-svg-KnDQYUzEEOijtRL1 .node.clickable{cursor:pointer;}#mermaid-svg-KnDQYUzEEOijtRL1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KnDQYUzEEOijtRL1 .arrowheadPath{fill:#333333;}#mermaid-svg-KnDQYUzEEOijtRL1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KnDQYUzEEOijtRL1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KnDQYUzEEOijtRL1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KnDQYUzEEOijtRL1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KnDQYUzEEOijtRL1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KnDQYUzEEOijtRL1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KnDQYUzEEOijtRL1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KnDQYUzEEOijtRL1 .cluster text{fill:#333;}#mermaid-svg-KnDQYUzEEOijtRL1 .cluster span{color:#333;}#mermaid-svg-KnDQYUzEEOijtRL1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KnDQYUzEEOijtRL1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KnDQYUzEEOijtRL1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-KnDQYUzEEOijtRL1 .icon-shape,#mermaid-svg-KnDQYUzEEOijtRL1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KnDQYUzEEOijtRL1 .icon-shape p,#mermaid-svg-KnDQYUzEEOijtRL1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KnDQYUzEEOijtRL1 .icon-shape .label rect,#mermaid-svg-KnDQYUzEEOijtRL1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KnDQYUzEEOijtRL1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KnDQYUzEEOijtRL1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KnDQYUzEEOijtRL1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 高可用
弹性扩展
安全隔离
集成
保护
API调用
事件推送
Okta云端服务
多区域部署
美国、欧盟、亚太
自动扩展架构
租户隔离
每个客户独立租户
企业客户
企业应用
如Salesforce、AWS、Office 365
开发者API
RESTful、GraphQL
事件钩子
用户变更实时通知
架构优势:
- 100%云端原生:
- 无需部署本地服务器
- 自动更新和维护
- 99.99% SLA可用性保证
- 全球分布式架构:
- 多数据中心部署
- 自动故障转移
- 数据驻留选项(美国、欧盟、加拿大、澳大利亚等)
- 安全性:
- SOC 2 Type II、ISO 27001、ISO 27018认证,FedRAMP Moderate认证(美国政府)
- 所有数据传输使用TLS 1.2+
全面支持现代身份认证标准:
| 协议/标准 | 支持情况 | 说明 |
|---|---|---|
| OIDC | 完整支持 | 作为IdP和SP,支持所有标准Flow |
| OAuth2.0 | 完整支持 | 支持所有授权模式,包括PKCE |
| SAML2.0 | 完整支持 | 作为IdP,支持SP-initiated和IdP-initiated |
| WS-Federation | 支持 | 主要用于集成Microsoft生态系统 |
| SCIM2.0 | 完整支持 | 自动化用户和组管理 |
| LDAP | 支持 | 通过Okta LDAP Agent集成 |
| RADIUS | 支持 | 用于VPN和Wi-Fi认证 |
| FIDO2/WebAuthn | 完整支持 | 无密码认证 |
提供丰富API和集成能力:
- REST API:
- Users API:用户生命周期管理
- Groups API:组和组成员管理
- Apps API:应用分配和管理
- Sessions API:会话管理
- Logs API:审计日志查询
- SDK支持:
- 前端:React、Vue、Angular、iOS、Android
- 后端:Node.js、Java、Python、.NET、Go、PHP
- 预集成应用库:
- 7k+预集成应用,如AWS、Salesforce、Slack、Office 365
- 一键配置SSO
- 自动化用户配置(Provisioning)
API调用示例:
js
// 使用Okta Management API创建用户
const okta = require('@okta/okta-sdk-nodejs');
const client = new okta.Client({
orgUrl: 'https://{your-okta-domain}.okta.com',
token: 'API_TOKEN',
});
async function createUser() {
const newUser = {
profile: {
firstName: 'Johnny',
lastName: 'Wong',
email: 'Johnny.Wong@awesome.com',
login: 'Johnny.Wong@awesome.com',
},
credentials: {
password: {
value: 'SecurePassword123!',
},
},
};
try {
const user = await client.createUser(newUser);
console.log('用户创建成功:', user.id);
// 分配用户到应用
await client.assignUserToApplication('APP_ID', user.id, {
scope: 'USER',
});
console.log('用户已分配到应用');
} catch (err) {
console.error('创建用户失败:', err);
}
}
createUser();
OIDC配置示例(Okta作为IdP):
js
// 使用 Okta OIDC 中间件(Node.js)
const { OktaAuth } = require('@okta/okta-auth-js');
const ExpressOIDC = require('@okta/okta-express-middleware');
const oidc = new ExpressOIDC({
issuer: 'https://{your-okta-domain}.okta.com/oauth2/default',
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
appBaseUrl: 'http://localhost:3000',
scope: 'openid profile email',
});
app.use(oidc.router);
// 受保护的路由
app.get('/dashboard', oidc.ensureAuthenticated(), (req, res) => {
// req.userinfo 包含用户信息
res.render('dashboard', { user: req.userinfo });
});
Auth0
官网,Identity As A Service提供商,可用于实现单点登录、无密码、MFA、社交网络认证、基于令牌的认证等,集成更改密码和忘记密码流程。官方文档。
已被Okta收购,成为Okta旗下的开发者优先(Developer-First) 身份平台。
定位差异:
| 特性 | Okta | Auth0 |
|---|---|---|
| 目标用户 | 企业IT团队 | 开发者和产品团队 |
| 主要场景 | Workforce Identity(员工) | Customer Identity(客户) |
| 定制灵活性 | 中等(低代码配置) | 高(代码优先,规则引擎) |
| 定价模式 | 按用户数 | 按MAU(月活跃用户) |
| 开发者体验 | 良好 | 优秀(文档、QuickStart、社区) |
协同效应:
- Okta提供企业级IAM能力
- Auth0提供开发者友好的B2C身份管理
- 两者共享部分技术栈,但保持独立产品路线
核心优势:
- 规则引擎(Rules):
- 使用JavaScript自定义认证流程
- 在用户登录时动态修改Token和用户信息
- 支持异步操作(如调用外部API)
- Hooks(钩子):
- 在认证流程的特定节点执行自定义逻辑
- 支持
Node.js代码 - 可用于审计、通知、数据同步等
- 自定义数据库连接:
- 连接到现有用户数据库,如MySQL、MongoDB等
- 无需迁移用户,平滑迁移到 Auth0
- 支持自定义密码哈希验证
- 无密码认证:
- 邮件链接登录
- SMS/WhatsApp OTP
- 生物识别:WebAuthn、FIDO2
实战
官方提供React、Angular、Next.js、iOS、Android、Java、.NET、Python等语言SDK。
Rules示例:
js
// Auth0 Rule:在登录时调用外部 API 丰富用户信息
function enrichUserProfile(user, context, callback) {
const axios = require('axios');
// 仅对新用户执行
if (context.stats.loginsCount > 1) {
return callback(null, user, context);
}
// 调用外部 API 获取用户积分
axios.get(`https://api.awesome.com/users/${user.user_id}/points`)
.then(response => {
const points = response.data.points;
// 将积分信息添加到 ID Token
context.idToken['https://awesome.com/points'] = points;
// 根据用户积分设置角色
if (points > 1000) {
context.idToken['https://awesome.com/role'] = 'vip';
}
callback(null, user, context);
})
.catch(err => {
console.log('调用 API 失败:', err);
callback(null, user, context); // 不影响登录流程
});
}
Hooks示例:
js
// Auth0 Hook:用户注册后发送欢迎邮件
module.exports = function (user, context, cb) {
const sendgrid = require('@sendgrid/mail');
sendgrid.setApiKey(context.wehook.secrets.SENDGRID_API_KEY);
const msg = {
to: user.email,
from: 'welcome@awesome.com',
subject: '欢迎加入我们的平台!',
html: `
<h1>欢迎,${user.name}!</h1>
<p>感谢您注册我们的服务。立即开始探索:</p>
<a href="https://awesome.com/dashboard">前往控制台</a>
`,
};
sendgrid.send(msg)
.then(() => {
console.log('欢迎邮件已发送');
cb(null, { user, context });
})
.catch(err => {
console.error('发送邮件失败:', err);
cb(null, { user, context }); // 不阻止注册流程
});
};
场景:使用Auth0保护React SPA和Node.js API
- React前端配置:
js
// React 应用:使用 @auth0/auth0-react
import { Auth0Provider } from '@auth0/auth0-react';
import { useAuth0 } from '@auth0/auth0-react';
function App() {
return (
<Auth0Provider
domain="YOUR_TENANT.auth0.com"
clientId="CLIENT_ID"
authorizationParams={{
redirect_uri: window.location.origin,
audience: "https://api.awesome.com", // API Identifier
scope: "openid profile email read:data",
}}
>
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<ProtectedDashboard />} />
</Routes>
</Router>
</Auth0Provider>
);
}
// 受保护的组件
function ProtectedDashboard() {
const { isAuthenticated, getAccessTokenSilently } = useAuth0();
const [data, setData] = useState(null);
useEffect(() => {
if (isAuthenticated) {
// 调用受保护的API
getAccessTokenSilently()
.then(token => {
return fetch('https://api.awesome.com/data', {
headers: {
Authorization: `Bearer ${token}`,
},
});
})
.then(res => res.json())
.then(data => setData(data));
}
}, [isAuthenticated, getAccessTokenSilently]);
return <div>Dashboard: {JSON.stringify(data)}</div>;
}
Node.jsAPI配置:
js
// Node.js Express API:使用 express-oauth2-jwt-bearer
const { auth } = require('express-oauth2-jwt-bearer');
const express = require('express');
const app = express();
// 1. 验证 Auth0 Access Token
const checkJwt = auth({
audience: 'https://api.awesome.com', // 必须与前端的 audience 匹配
issuerBaseURL: `https://YOUR_TENANT.auth0.com/`,
});
// 2. 受保护的路由
app.get('/data', checkJwt, (req, res) => {
// req.auth包含解码后的Access Token信息
const userId = req.auth.sub;
const permissions = req.auth.permissions; // 需配置API Authorization
res.json({
message: '这是受保护的数据',
userId: userId,
permissions: permissions,
});
});
// 3. 基于权限的访问控制(RBAC)
const checkPermission = (requiredPermission) => {
return (req, res, next) => {
const userPermissions = req.auth.permissions || [];
if (!userPermissions.includes(requiredPermission)) {
return res.status(403).json({ error: '权限不足' });
}
next();
};
};
app.post('/data', checkJwt, checkPermission('write:data'), (req, res) => {
// 仅允许有 write:data 权限的用户
res.json({ message: '数据已创建' });
});
app.listen(3000, () => console.log('API运行在端口3000'));
AWS Cognito
Amazon Cognito是AWS提供的身份认证和访问控制服务,专为移动和Web应用设计。
核心组件:
- User Pools(用户池):
- 作用:用户目录,提供注册、登录、配置文件管理功能
- 支持的协议:OIDC、OAuth 2.0
- Token类型:ID Token(JWT)、Access Token、Refresh Token
- 用户存储:Cognito托管,自动扩展至数百万用户
- Identity Pools(身份池,原Federated Identities):
- 作用:提供临时AWS凭证,用于访问AWS资源,如S3等
- 身份来源:
- 已认证用户:通过User Pool或第三方IdP
- 未认证用户:Guest Access
- 凭证类型:临时AWS IAM凭证(STS)
对比:
| 特性 | 用户池 | 身份池 |
|---|---|---|
| 主要目的 | 用户身份认证 | AWS资源访问授权 |
| 返回内容 | JWT Token(IDToken、AccessToken) | 临时AWS凭证(AccessKey、SecretKey、SessionToken) |
| 适用场景 | 应用登录、用户信息管理 | 访问S3桶、调用API Gateway、读写DynamoDB |
| 用户存储 | Cognito托管 | 不存储用户,仅颁发凭证 |
| 协议支持 | OIDC、OAuth2.0、SAML2.0 | AWS STS、OIDC(通过用户池交换) |
集成架构:
AWS资源 身份池 用户池 应用 用户 AWS资源 身份池 用户池 应用 用户 #mermaid-svg-Z8cWIA4IcQgi95H4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Z8cWIA4IcQgi95H4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Z8cWIA4IcQgi95H4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Z8cWIA4IcQgi95H4 .error-icon{fill:#552222;}#mermaid-svg-Z8cWIA4IcQgi95H4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Z8cWIA4IcQgi95H4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Z8cWIA4IcQgi95H4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Z8cWIA4IcQgi95H4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Z8cWIA4IcQgi95H4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Z8cWIA4IcQgi95H4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Z8cWIA4IcQgi95H4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Z8cWIA4IcQgi95H4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Z8cWIA4IcQgi95H4 .marker.cross{stroke:#333333;}#mermaid-svg-Z8cWIA4IcQgi95H4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Z8cWIA4IcQgi95H4 p{margin:0;}#mermaid-svg-Z8cWIA4IcQgi95H4 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Z8cWIA4IcQgi95H4 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-Z8cWIA4IcQgi95H4 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Z8cWIA4IcQgi95H4 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-Z8cWIA4IcQgi95H4 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-Z8cWIA4IcQgi95H4 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-Z8cWIA4IcQgi95H4 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-Z8cWIA4IcQgi95H4 .sequenceNumber{fill:white;}#mermaid-svg-Z8cWIA4IcQgi95H4 #sequencenumber{fill:#333;}#mermaid-svg-Z8cWIA4IcQgi95H4 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-Z8cWIA4IcQgi95H4 .messageText{fill:#333;stroke:none;}#mermaid-svg-Z8cWIA4IcQgi95H4 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Z8cWIA4IcQgi95H4 .labelText,#mermaid-svg-Z8cWIA4IcQgi95H4 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-Z8cWIA4IcQgi95H4 .loopText,#mermaid-svg-Z8cWIA4IcQgi95H4 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-Z8cWIA4IcQgi95H4 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Z8cWIA4IcQgi95H4 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Z8cWIA4IcQgi95H4 .noteText,#mermaid-svg-Z8cWIA4IcQgi95H4 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-Z8cWIA4IcQgi95H4 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Z8cWIA4IcQgi95H4 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Z8cWIA4IcQgi95H4 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Z8cWIA4IcQgi95H4 .actorPopupMenu{position:absolute;}#mermaid-svg-Z8cWIA4IcQgi95H4 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-Z8cWIA4IcQgi95H4 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Z8cWIA4IcQgi95H4 .actor-man circle,#mermaid-svg-Z8cWIA4IcQgi95H4 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-Z8cWIA4IcQgi95H4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1. 登录请求 2. 认证请求 3. 验证凭据 4. 返回ID Token + Access Token 5. 交换AWS凭证 (携带ID Token) 6. 验证Token,颁发IAM角色 7. 返回临时AWS凭证 8. 使用AWS凭证访问资源 9. 返回数据
与AWS服务的深度集成:
- Amazon API Gateway:
- 使用Cognito User Pool Authorizer保护API
- 自动验证JWT Token
- 支持自定义Scopes进行细粒度授权
- AWS Amplify:
-前端库(React、Vue、Angular、React Native)- 自动配置用户池和身份池
- 提供认证UI组件(Amplify UI)
- AWS Lambda:
- 触发器(Triggers):在用户注册、登录、忘记密码等事件时触发Lambda
- 自定义认证流程:使用Lambda实现自定义Challenge-Response认证
- Amazon S3:
- 使用身份池获取临时凭证
- 基于IAM策略实现细粒度的S3桶访问控制
局限性:
- 自定义UI受限:
- 托管UI自定义能力有限
- 需要使用Amplify UI或自定义登录页面
- Lambda 触发器调试困难:
- 错误信息不够详细
- 需使用CloudWatch Logs调试
- 用户迁移复杂:
- 不支持直接导入密码哈希
- 需要使用"Migration Lambda"在用户首次登录时迁移
- Group数量限制:
- 每个用户池最多1w个组
- 每个用户最多100个组
实战
API Gateway集成Cognito示例:
js
// AWS CDK定义:API Gateway使用Cognito授权
import * as cdk from 'aws-cdk-lib';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as cognito from 'aws-cdk-lib/aws-cognito';
const userPool = new cognito.UserPool(this, 'MyUserPool', {
userPoolName: 'my-app-user-pool',
selfSignUpEnabled: true,
signInAliases: {
email: true,
},
});
const userPoolClient = new cognito.UserPoolClient(this, 'MyUserPoolClient', {
userPool: userPool,
oAuth: {
flows: {
authorizatonCodeGrant: true,
},
scopes: [cognito.OAuthScope.OPENID, cognito.OAuthScope.EMAIL],
},
});
// API Gateway 使用 Cognito 授权
const api = new apigateway.RestApi(this, 'MyApi', {
restApiName: 'My Protected API',
});
const authorizer = new apigateway.CognitoUserPoolsAuthorizer(this, 'MyAuthorizer', {
cognitoUserPools: [userPool],
});
const protectedResource = api.root.addResource('protected');
protectedResource.addMethod('GET', new apigateway.MockIntegration(), {
authorizer: authorizer,
authorizationType: apigateway.AuthorizationType.COGNITO,
});
Cognito支持通过Lambda触发器自定义认证流程:
可用Lambda触发器:
| 触发器 | 触发时机 | 用途 |
|---|---|---|
| Pre Sign-up | 用户注册前 | 自动确认用户、拒绝特定邮箱域名 |
| Post Confirmation | 用户确认邮箱后 | 发送欢迎邮件、添加用户到数据库 |
| Pre Authentication | 用户登录前 | 实施自定义验证规则(如IP黑名单) |
| Post Authentication | 用户登录后 | 记录登录日志、触发MFA |
| Custom Message | 发送验证邮件/短信前 | 自定义邮件/短信内容 |
| Forgot Password | 用户忘记密码 | 自定义密码重置逻辑 |
自定义认证流程示例(使用挑战-响应):
js
// Lambda 触发器:定义自定义认证挑战
exports.handler = async (event) => {
if (event.triggerSource === 'DefineAuthChallenge') {
// 检查用户是否已通过所有挑战
if (event.request.session.length === 0) {
// 第一个挑战:输入 OTP
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'CUSTOM_CHALLENGE';
} else if (event.request.session[0].challengeName === 'CUSTOM_CHALLENGE' &&
event.request.session[0].challengeResult === true) {
// 用户已通过 OTP 验证
event.response.issueTokens = true;
event.response.failAuthentication = false;
} else {
// 验证失败
event.response.issueTokens = false;
event.response.failAuthentication = true;
}
}
return event;
};
// Lambda 触发器:创建自定义挑战(发送 OTP)
exports.handler = async (event) => {
if (event.triggerSource === 'CreateAuthChallenge') {
const otp = Math.floor(100000 + Math.random() * 900000); // 6位 OTP
// 将 OTP 存储到 Redis(用于后续验证)
await redis.setex(`otp:${event.request.userName}`, 300, otp);
// 发送 OTP 到用户手机(使用 Amazon SNS)
await sns.publish({
Message: `您的验证码是:${otp},5分钟内有效。`,
PhoneNumber: event.request.userAttributes.phone_number,
}).promise();
// 将 OTP 返回给客户端(用于验证)
event.response.publicChallengeParameters = {
phone: event.request.userAttributes.phone_number,
};
event.response.privateChallengeParameters = {
otp: otp.toString(),
};
}
return event;
};
// Lambda触发器:验证自定义挑战
exports.handler = async (event) => {
if (event.triggerSource === 'VerifyAuthChallengeResponse') {
const expectedOtp = await redis.get(`otp:${event.request.userName}`);
const providedOtp = event.request.challengeAnswer;
if (expectedOtp === providedOtp) {
event.response.answerCorrect = true;
await redis.del(`otp:${event.request.userName}`);
} else {
event.response.answerCorrect = false;
}
}
return event;
};
最佳实践:
- 使用Amplify客户端库:自动处理Token刷新、提供现成的UI组件
- 为生产环境启用MFA:如TOTP(Google Authenticator),或使用SMS/Email OTP
- 使用自定义域名:避免使用默认的
*.auth.region.amazoncognito.com域名,提升品牌形象和用户信任 - 设置Token有效期:Access Token推荐5-60分钟、Refresh Token推荐1-365天、根据应用安全需求调整
- 使用App Client Secret:
- 对于服务器端应用,启用App Client Secret
- 对于 SPA 和移动应用,不要启用(无法安全存储Secret)
不推荐做法:
- 不要将敏感信息存储在ID Token中:ID Token能被客户端解码,使用Access Token或调用
/userinfo端点 - Cognito是用于认证,认证成功后将用户配置文件存储在外部数据库如DynamoDB
- 不要在Lambda触发器中执行长时间操作:Lambda触发器有超时限制(默认5秒),长时间操作应使用异步方式,如SQS
成本优化建议:
- 用户池:免费层(5w MAU),之后$0.0055/MAU
- 身份池:免费(仅收取AWS资源使用费用)
- 优化建议:
- 使用Refresh Token减少Token刷新频率
- 对于Guest Access,使用未经身份验证的角色(控制权限)
- 监控MAU数量,避免不必要的活跃用户
ForgeRock
提供完整的身份平台,涵盖IAM、IGA、CIAM和MFA等;已被 Ping Identity收购,其技术平台与产品已整合进后者的身份管理平台,形成更全面的混合云身份和IAM解决方案。
从开源项目主页能看到其核心产品矩阵:
- Access Management(AM):
- 认证和授权服务器
- 支持OIDC、OAuth 2.0、SAML 2.0
- 策略决策点(PDP)和政策执行点(PEP)
- Identity Management(IDM):
-用户生命周期管理- 工作流和审批流程
- 连接器框架(连接到LDAP、AD、数据库等)
- Directory Services(DJ):
- 基于Java开发、高性能LDAP和REST目录服务
- 支持多主复制(Multi-master Replication)
- 适用于大规模用户存储
- Identity Gateway(IG):
- 反向代理和策略执行点
- 保护遗留应用(无需修改代码)
- 支持WebSocket和微服务
踩坑注意:这四个产品都有对应的,基于Java语言开发,开源社区版本,但已不再维护。
特色功能:
- IoT身份认证:支持设备认证和授权
- 隐私和同意管理:符合GDPR的用户同意管理
- AI驱动的安全:使用机器学习检测异常行为
适用场景:
- 电信运营商(需要管理数百万用户)
- IoT平台(需要设备身份认证)
- 需要隐私合规的企业(如GDPR、CCPA)
IBM Security Verify
IBM云原生身份即服务(IDaaS)平台,整合IAM和CIAM能力。