使用 AWS Cognito 和子域的 SSO
Posted
技术标签:
【中文标题】使用 AWS Cognito 和子域的 SSO【英文标题】:SSO with AWS Cognito and Sub Domains 【发布时间】:2017-10-14 22:59:00 【问题描述】:我可以使用 AWS Cognito 轻松地将身份信息传递到多个子域吗?如果我有三个应用程序(app1.example.com、app2.example.com、app3.example.com),如何登录 app1,然后将身份信息传递给 app2 和 app3?我已经阅读了文档并看到了诸如 getIdToken().getJwtToken
之类的方法,但我还没有看到如何将这些数据传递给以便我可以使用身份。
//Login.ts
let cognitoUser = new CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, function()
onSuccess: function(result)
let jwt = result.getIdToken().getJwtToken();
//Is it possible to pass this jwt token (or something else)
//to app2 and app3 so I can later fetch the user from the identity pool from those apps?
);
【问题讨论】:
【参考方案1】:您可以在创建 CognitoUserPool 对象时使用 JS SDK 中的 CookieStorage class 跨所有子域实现 SSO。当从 Cognito 接收到的身份验证令牌存储在 cookie(而不是 LocalStorage)中时,它们也可用于所有子域。因此调用 CognitoUserPool.getCurrentUser() 和 CognitoUserPool.getSession() 将返回来自所有子域的令牌。
TypeScript 代码 sn-ps 下面
完整的实现可以在here找到。可以查看正在运行的应用程序here。
对用户进行身份验证(在主域上,例如 example.com)-
signIn(email: string, password: string): Observable<any>
let userPool = new CognitoUserPool(
UserPoolId: environment._USER_POOL_ID,
ClientId: environment._CLIENT_ID,
Storage: new CookieStorage(secure: false, domain: "example.com"),
);
let authenticationDetails = new AuthenticationDetails(
Username: email,
Password: password,
);
let userData =
Username: email,
Pool: userPool,
Storage: new CookieStorage(secure: false, domain: "example.com"),
;
let cognitoUser = new CognitoUser(userData);
return Observable.create((observer: Observer<any>) =>
cognitoUser.authenticateUser(authenticationDetails,
onSuccess: result =>
observer.next(result);
observer.complete();
,
onFailure: error => observer.error(error),
);
);
检查用户是否经过身份验证(在子域上,例如 sub.example.com)
isAuthenticated(): Observable<boolean>
let userPool = new CognitoUserPool(
UserPoolId: environment._USER_POOL_ID,
ClientId: environment._CLIENT_ID,
Storage: new CookieStorage(secure: false, domain: "example.com"),
);
let cognitoUser = userPool.getCurrentUser();
if (cognitoUser != null)
return Observable.create((observer: Observer<boolean>) =>
cognitoUser.getSession((error, session) =>
if (error)
console.error(error);
observer.next(false);
observer.complete();
console.log(session, session.isValid(), session.isAuthenticated);
observer.next(session.isValid());
observer.complete();
);
)
【讨论】:
【参考方案2】:首先,应用程序子域与 AWS Cognito 没有直接连接。
如果您有子域并且需要使用单个 Cognito 用户池对用户进行身份验证,同时还要检查身份与子域的链接(假设用户注册时,他们是从特定的子域应用程序注册的),您需要将其存储Cognito 用户中的自定义属性或与 Cognito ID 和子域链接的存储后端中的信息,并在用户身份验证时在代码中进行验证。
//Login.ts
let cognitoUser = new CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, function()
onSuccess: function(result)
// Also check the user custom attribute comparing with the request subdomain.
let jwt = result.getIdToken().getJwtToken();
//You can pass this jwt token back to the client
//Each app can later fetch user data from identity pool
);
注意:如果您使用托管 UI 进行登录,流程可能会略有不同,因为您需要为每个子域创建三个具有不同回调 url 的客户端应用程序。
我正在尝试开发类似于 Google 身份验证流程的解决方案。 您登录到 accounts.google.com 一次,然后该会话用于 mail.google.com、news.google.com 等,无需登录 每个应用程序手动。登录 accounts.myapp.com 后,我需要 将用户的身份验证传递给 mail.myapp.com 和 news.myapp.com。我不 在 AWS 文档中查看我如何创建 Cognito 客户端的实例 (来自 mail.myapp.com 或 news.myapp.com)来自创建的身份 account.myapp.com
这可以使用 Cognito 用户池来实现。
创建一个 API 端点,它将在验证用户凭据(例如用户名和密码)后发出 JWT 令牌。检查this 示例中的验证用户部分。 从您的前端应用调用此 API 并将 JWT 存储在浏览器存储中(例如 LocalStorage、SessionStorage)。 对于未来的 API 调用,将 JWT 包含在标头中并发送到您的 API,API 将在其中验证 JWT 令牌。有关更多详细信息,请查看 this 文档中的在 Web API 中使用 ID 令牌和访问令牌部分。【讨论】:
将result.getIdToken().getJwtToken()
的结果传递给其他应用程序后,如何获取用户数据?我找不到此步骤的文档。
您自己获得的 JWT 令牌包含以 base64 编码的用户声明。使用 jwt 解码机制来提取属性。
如何使用 JWT 从其他应用程序实例化 AWS 开发工具包实例?我没有看到允许这样做的 API。
例如,假设您将 jwt 从您的 Web 应用程序转发到 nodejs 服务器。从节点 js 服务器,您将能够验证 jwt。由于 jwt 是一种标准,因此您不需要 AWS 开发工具包对其进行解码。使用任何可用的 jwt 库来解码和验证 jwt。
@user1007817 你找到在不同子域或不同应用之间共享令牌的解决方案了吗以上是关于使用 AWS Cognito 和子域的 SSO的主要内容,如果未能解决你的问题,请参考以下文章
使用 AWS Amplify 和 AWS Cognito 进行数据特定授权