#aws-lambda #amazon-cognito
#aws-lambda #amazon-cognito
Вопрос:
В настоящее время я создаю решение для миграции из пользовательского пула AWS в другой, используя CognitoTrigger «Миграция пользователей».
У меня есть группа, которую я хочу установить во время миграции, но я не могу этого сделать, потому что пользователь не создается до завершения всего контекста.
Как я могу это решить? Я не хочу создавать PostAuth — lambda, потому что мне нужно / хочу / могу запускать это только один раз за миграцию, и я также хочу сделать это сразу (или через несколько минут), когда произойдет миграция. (или можно ли выполнить эту проверку после авторизации, если она запускается в первый раз?)
Я попробовал PostConfirm в надежде, что это сработает при создании пользователя, но это не сработало.
Комментарии:
1. Я пытаюсь добиться того же самого. Вы решили это?
2. Нет, это было невозможно. После этого я сделал это с помощью скрипта.
3. Я пытаюсь то же самое… Как вы думаете, может быть, мы могли бы использовать эту идею в статье aws.amazon.com/blogs/mobile/… обработка «вручную» вместо уверенности в Cognito?
Ответ №1:
Если кто-то еще столкнется с этим — я решил это, используя комбинацию триггера миграции пользователя и триггера предварительной генерации токена.
В пользовательском триггере миграции (в основном скопированном из https://github.com/Collaborne/migrate-cognito-user-pool-lambda ) найдите и создайте пользователя, если сбой аутентификации / пользователь не существует в новом пуле.
В триггере предварительной генерации токена, если пользователь еще не добавлен в группы, найдите членство в группах в старом пуле пользователей ( adminListGroupsForUser
), добавьте их в новый пул ( adminAddUserToGroup
). Важной частью является переопределение утверждений о членстве в группе в ответе, чтобы они были добавлены к токену на стороне клиента ( groupsToOverride
это просто массив имен групп, частью которых является пользователь):
event.response = {
"claimsOverrideDetails": {
"claimsToAddOrOverride": {
},
"groupOverrideDetails": {
"groupsToOverride": groupsToOverride,
}
}
};
Комментарии:
1. Как узнать, в какую группу следует добавить пользователя в этой части миграции?
2. вы просматриваете их в старом пуле — например
data = await cognitoidentityserviceprovider.adminListGroupsForUser(paramsOldPool).promise();
Ответ №2:
Спасибо @BrokenGlass, я использовал этот подход. Для всех остальных вот пример Typescript preTokenGeneration lambda.
//preTokenGenerations.ts
import { PreTokenGenerationTriggerHandler } from 'aws-lambda';
import { preTokenAuthentication } from '../services/preTokenService';
export const handler: PreTokenGenerationTriggerHandler = async (event, context) => {
console.log({
event,
context,
request: event.request,
userAttributes: event.request.userAttributes,
clientMetadata: event.request.clientMetadata,
groupConfiguration: event.request.groupConfiguration,
})
const OLD_USER_POOL_ID = process.env.OLD_USER_POOL_ID;
if (!OLD_USER_POOL_ID) {
throw new Error("OLD_USER_POOL_ID is required for the lambda to work.")
}
const {
userPoolId,
request: {
userAttributes: {
email
}
},
region
} = event;
switch (event.triggerSource) {
case "TokenGeneration_Authentication":
const groupsToOverride = await preTokenAuthentication({
userPoolId,
oldUserPoolId: OLD_USER_POOL_ID,
username: email,
region
})
event.response = {
"claimsOverrideDetails": {
"claimsToAddOrOverride": {
},
"groupOverrideDetails": {
"groupsToOverride": groupsToOverride,
}
}
};
return event
default:
console.log(`Bad triggerSource ${event.triggerSource}`);
return new Promise((resolve) => {
resolve(event)
});
}
}
// preTokenService.ts
import { getUsersGroups, cognitoIdentityServiceProvider, assignUserToGroup } from "./cognito"
interface IPreTokenAuthentication {
userPoolId: string;
oldUserPoolId: string;
username: string;
region: string
}
export const preTokenAuthentication = async ({ userPoolId, oldUserPoolId, username, region }: IPreTokenAuthentication): string[] => {
const cognitoISP = cognitoIdentityServiceProvider({ region });
const newPoolUsersGroups = await getUsersGroups({
cognitoISP,
userPoolId,
username
});
// If the user in the new pool already has groups assigned then exit
if (newPoolUsersGroups.length !== 0) {
console.log("No action required user already exists in a group")
return;
}
const oldPoolUsersGroups = await getUsersGroups({
cognitoISP,
userPoolId: oldUserPoolId,
username
});
// If the user in the old pool doesn't have any groups then nothing else for this function to do so exit.
if (oldPoolUsersGroups.length === 0) {
console.error("No action required user migrated user didn't belong to a group")
return;
}
console.log({ oldPoolUsersGroups, newPoolUsersGroups })
await assignUserToGroup({
cognitoISP,
userPoolId,
username,
groups: oldPoolUsersGroups
})
return oldPoolUsersGroups;
}
// cognito.ts
import { AdminAddUserToGroupRequest, AdminListGroupsForUserRequest } from "aws-sdk/clients/cognitoidentityserviceprovider";
import { CognitoIdentityServiceProvider } from 'aws-sdk';
interface ICognitoIdentityServiceProvider {
region: string;
}
export const cognitoIdentityServiceProvider = ({ region }: ICognitoIdentityServiceProvider) => {
const options: CognitoIdentityServiceProvider.Types.ClientConfiguration = {
region,
};
const cognitoIdentityServiceProvider = new CognitoIdentityServiceProvider(options);
return cognitoIdentityServiceProvider;
}
interface IGetUsersGroups {
cognitoISP: CognitoIdentityServiceProvider,
userPoolId: string,
username: string
}
export const getUsersGroups = async ({ cognitoISP, userPoolId, username }: IGetUsersGroups): Promise<string[]> => {
try {
const params: AdminListGroupsForUserRequest = {
UserPoolId: userPoolId,
Username: username,
}
const response = await cognitoISP.adminListGroupsForUser(params).promise();
return response.Groups?.map(group => group.GroupName!) || [];
} catch (err) {
console.error(err)
return [];
}
}
interface IAssignUserToGroup {
cognitoISP: CognitoIdentityServiceProvider,
username: string;
groups: string[];
userPoolId: string;
}
/**
* Use Administration to assign a user to groups
* @param {
* cognitoISP the cognito identity service provider to perform the action on
* userPoolId the userPool for which the user is being modified within
* username the username or email for which the action is to be performed
* groups the groups to assign the user too
* }
*/
export const assignUserToGroup = async ({ cognitoISP, userPoolId, username, groups }: IAssignUserToGroup) => {
console.log({ userPoolId, username, groups })
for (const group of groups) {
const params: AdminAddUserToGroupRequest = {
UserPoolId: userPoolId,
Username: username,
GroupName: group
};
try {
const response = await cognitoISP.adminAddUserToGroup(params).promise();
console.log({ response })
} catch (err) {
console.error(err)
}
}
}
Советы, убедитесь, что в разделе триггера в Cognito установлены триггеры миграции и предварительного запуска. Вам также необходимо убедиться, что SRP не включен, чтобы lambda мог видеть пароль для успешной миграции пользователя.
Что нужно проверить, так это то, что при первом переносе пользователю назначаются их группы. И для будущих логинов они также назначаются своим группам.
Дайте мне знать, если у кого-нибудь есть какие-либо отзывы или вопросы, рад помочь.