问题描述: 我在尝试使用 OIDC (OpenID Connect) 协议向 AWS Cognito 用户池中的现有用户添加身份提供商 (IdP) 时遇到了挑战。
症状: 难以确定将 OIDC 提供商链接到现有用户的适当方法。 不确定使用哪些 API 操作和参数来链接提供者。
这是我在 Node-js 中预注册 lambda 函数的代码。
const {
CognitoIdentityProviderClient,
ListUsersCommand,
AdminLinkProviderForUserCommand,
} = require("@aws-sdk/client-cognito-identity-provider");
const cognitoClient = new CognitoIdentityProviderClient({});
exports.handler = async (event) => {
if (event.triggerSource === "PreSignUp_ExternalProvider") {
const {
userPoolId,
request: { userAttributes },
} = event;
const email = userAttributes["email"];
// Check if the email already exists
const userList = await cognitoClient.send(
new ListUsersCommand({
UserPoolId: userPoolId,
Filter: `email = "${email}"`,
})
);
if (userList.Users && userList.Users.length > 0) {
const [providerName, providerUserId] = event.userName.split("_");
let sourceProviderName;
let providerAttributeName;
switch (providerName) {
case "google":
sourceProviderName = "Google";
providerAttributeName = "Cognito_Subject";
break;
case "azureadidp":
sourceProviderName = "azureadidp";
providerAttributeName = "sub";
break;
default:
return event;
}
// Link the provider to the existing user
await cognitoClient.send(
new AdminLinkProviderForUserCommand({
DestinationUser: {
ProviderAttributeValue: userList.Users[0].Username,
ProviderName: "Cognito",
},
SourceUser: {
ProviderAttributeName: providerAttributeName,
ProviderAttributeValue: providerUserId,
ProviderName: sourceProviderName,
},
UserPoolId: userPoolId,
})
);
} else {
console.log("User not found, skipping link.");
}
}
return event;
};
尝试解决: 最初尝试使用 AdminLinkProviderForUserCommand 操作,但在识别正确参数时遇到问题。 研究了 AWS 文档和在线资源,但很难找到有关 OIDC 特定实施细节的明确指导。 请求协助: 我正在寻求有关将 OIDC 提供商(例如 Google 或 AzureAD)链接到 AWS Cognito 用户池中的现有用户的正确方法和具体步骤的指导。此外,我需要帮助来确定必要的 API 操作、参数以及成功实施所需的任何其他配置步骤。
据我观察,代码中的 providerUserId 在 OIDC 的情况下给出了不正确的大小写,因此通过创建自定义属性并将其从 OIDC 映射到 sub 并在应用程序集成部分中为自定义属性授予读取权限UserPool 然后从 event.request.userAttributes["custom:userid"] 在 lambda 函数中获取 providerUserId 它将正常工作。
这是我的 lambda 函数代码。
const {
CognitoIdentityProviderClient,
ListUsersCommand,
AdminLinkProviderForUserCommand,
} = require("@aws-sdk/client-cognito-identity-provider");
const cognitoClient = new CognitoIdentityProviderClient({});
const getProviderAttributeValueSource = (
providerName,
providerUserId,
event
) => {
switch (providerName) {
case "google":
return providerUserId;
case "microsoft":
return event.request.userAttributes["custom:userid"];
default:
return "";
}
};
const getProviderNameSource = (providerName) => {
switch (providerName) {
case "google":
return "Google";
case "microsoft":
return "Microsoft";
default:
return "";
}
};
exports.handler = async (event) => {
if (event.triggerSource === "PreSignUp_ExternalProvider") {
const {
userPoolId,
request: { userAttributes },
} = event;
const email = userAttributes["email"];
// Check if the email already exists
const userList = await cognitoClient.send(
new ListUsersCommand({
UserPoolId: userPoolId,
Filter: `email = "${email}"`,
})
);
if (userList.Users && userList.Users.length > 0) {
const providerName = event.userName.substr(
0,
event.userName.indexOf("_")
);
const providerUserId = event.userName.substr(
event.userName.indexOf("_") + 1
);
const jsonToAddProvider = {
DestinationUser: {
ProviderAttributeValue: userList.Users[0].Username,
ProviderName: "Cognito",
},
SourceUser: {
ProviderAttributeName: "Cognito_Subject",
ProviderAttributeValue: getProviderAttributeValueSource(
providerName,
providerUserId,
event
),
ProviderName: getProviderNameSource(providerName),
},
UserPoolId: userPoolId,
};
console.log("jsonToAddProvider : ", jsonToAddProvider);
// Link the provider to the existing user
const response = await cognitoClient.send(
new AdminLinkProviderForUserCommand(jsonToAddProvider)
);
console.log("response : ", response);
} else {
console.log("User not found, skipping link.");
}
}
return event;
};