管理アクションの設定
管理アクションを使用することで、Cognito ユーザープール内のユーザーとグループに対するクエリと操作を実行できます。
例えば、Cognito ユーザープール内のすべてのユーザーを一覧表示する機能は、ログインしているユーザーが「Admins」という特定のグループのメンバーである場合、アプリの管理パネルに役立つかもしれません。
これは高度な機能であり、基礎となるアーキテクチャを理解していない場合は推奨されません。作成される関連インフラストラクチャは、特定のビジネスニーズに合わせてカスタマイズするために設計された基盤です。アプリが必要としない機能は削除することをお勧めします。
Amplify CLI は、アプリケーションにこれらの機能が必要な場合、ユーザープールに対する制限されたアクセス許可で実行される Lambda 関数への安全なアクセスを備えた REST エンドポイントをセットアップできます。有効なアカウントを持つすべてのユーザーにアクションを公開するか、特定のユーザープールグループに制限するかを選択できます。
管理クエリを有効にする
amplify add auth手動構成を進むオプションを選択します。
Do you want to use the default authentication and security configuration? (Use arrow keys) Default configuration Default configuration with Social Provider (Federation) ❯ Manual configuration I want to learn more.次のプロンプトに到達するまで、残りの構成ステップを進みます。
? Do you want to add User Pool Groups? Yes? Provide a name for your user pool group: Admins? Do you want to add another User Pool Group No✔ Sort the user pool groups in order of preference · Admins? Do you want to add an admin queries API? Yes? Do you want to restrict access to the admin queries API to a specific Group? Yes? Select the group to restrict access with: (Use arrow keys)❯ Admins Enter a custom group残りのプロンプトで構成を完了します。
amplify update auth管理クエリ API を作成または更新するオプションを選択します。
What do you want to do? Create or update Admin queries API? Do you want to restrict access to the admin queries API to a specific Group Yes? Select the group to restrict access with: (Use arrow keys)❯ Admins Enter a custom group準備ができたら、amplify push を実行して変更をデプロイします。
これにより、Cognito Authorizer を使用する API Gateway エンドポイントが構成され、アクセストークンを受け入れます。このトークンは Lambda 関数がユーザープールに対してアクションを実行するために使用されます。この関数はサンプルコードであり、amplify/backend/function/AdminQueriesXXX/src ディレクトリで編集してから amplify push を実行して、ビジネスケースに基づいて機能を削除、追加、または変更するために使用できます。アクションを特定のグループに制限することを選択した場合、関数のカスタムミドルウェアはユーザーがそのグループのメンバーでない限り、すべてのアクションを防止します。
管理クエリ API
デフォルトのルートとその機能、HTTP メソッド、および予期されるパラメーターを以下に示します。
addUserToGroup: ユーザーを特定のグループに追加します。POST ボディにusernameとgroupnameが必要です。removeUserFromGroup: ユーザーを特定のグループから削除します。POST ボディにusernameとgroupnameが必要です。confirmUserSignUp: ユーザーのサインアップを確認します。POST ボディにusernameが必要です。disableUser: ユーザーを無効にします。POST ボディにusernameが必要です。enableUser: ユーザーを有効にします。POST ボディにusernameが必要です。getUser: 特定のユーザーの詳細を取得します。GET クエリ文字列としてusernameが必要です。listUsers: 現在の Cognito ユーザープール内のすべてのユーザーを一覧表示します。GET クエリ文字列としてオプションのlimit(0~60 の間)を指定できます。これにより、ページネーション用にtokenクエリ文字列として提供できるNextTokenが返されます。listGroups: 現在の Cognito ユーザープール内のすべてのグループを一覧表示します。GET クエリ文字列としてオプションのlimit(0~60 の間)を指定できます。これにより、ページネーション用にtokenクエリ文字列として提供できるNextTokenが返されます。listGroupsForUser: 現在のユーザーが属するグループを一覧表示します。GET クエリ文字列としてusernameが必要です。GET クエリ文字列としてオプションのlimit(0~60 の間)を指定できます。これにより、ページネーション用にtokenクエリ文字列として提供できるNextTokenが返されます。listUsersInGroup: 特定のグループに属するユーザーを一覧表示します。GET クエリ文字列としてgroupnameが必要です。GET クエリ文字列としてオプションのlimit(0~60 の間)を指定できます。これにより、ページネーション用にtokenクエリ文字列として提供できるNextTokenが返されます。signUserOut: ユーザープールからユーザーをサインアウトします。ただし、その呼び出しがそのユーザーから発信されている場合のみです。POST ボディにusernameが必要です。
例
アプリでこの機能を活用するには、サインイン後に Amplify.API から適切なルートを呼び出します。次の例は、ユーザー「richard」をエディターグループに追加し、ページネーション制限が 10 のエディターグループのすべてのメンバーを一覧表示します。
import React from 'react'import { Amplify } from 'aws-amplify';import { fetchAuthSession } from 'aws-amplify/auth';import { post } from 'aws-amplify/api'import { withAuthenticator } from '@aws-amplify/ui-react';import '@aws-amplify/ui-react/styles.css';
import amplifyconfig from './amplifyconfiguration.json';Amplify.configure(amplifyconfig);
const client = generateClient()
async function addToGroup() { let apiName = 'AdminQueries'; let path = '/addUserToGroup'; let options = { body: { "username" : "richard", "groupname": "Editors" }, headers: { 'Content-Type' : 'application/json', Authorization: `${(await fetchAuthSession()).tokens.accessToken}` } } return post({apiName, path, options});}
async function listEditors(limit){ let apiName = 'AdminQueries'; let path = '/listUsersInGroup'; let options = { queryParams: { "groupname": "Editors", "limit": limit, }, headers: { 'Content-Type' : 'application/json', Authorization: `${(await fetchAuthSession()).tokens.accessToken}` } } const response = await get({apiName, path, options}); return response;}
function App() { return ( <div className="App"> <button onClick={addToGroup}>Add to Group</button> <button onClick={() => listEditors(10)}>List Editors</button> </div> );}
export default withAuthenticator(App);- Amplify API を初期化します。詳細は Set up Amplify REST API を参照してください。
インポートを含める初期化コードを用意しておく必要があります。
import Amplifyimport AWSCognitoAuthPluginimport AWSAPIPluginおよび Amplify を構成する前に AWSCognitoAuthPlugin と AWSAPIPlugin を追加するコード。
try Amplify.add(plugin: AWSCognitoAuthPlugin())try Amplify.add(plugin: AWSAPIPlugin())try Amplify.configure()-
Amplify.Authを使用してサインインします。ユーザーのサインアップとサインインの詳細については、Amplify.Auth を参照してください。 -
アプリで以下を使用して、ユーザーをグループに追加します。
func addToGroup(username: String, groupName: String) async { let path = "/addUserToGroup" let body = "{\"username\":\"\(username)\",\"groupname\":\"\(groupName)\"}".data(using: .utf8) let request = RESTRequest(path: path, body: body) do { let data = try await Amplify.API.post(request: request) print("Response Body: \(String(decoding: data, as: UTF8.self))") } catch { if case let .httpStatusError(statusCode, response) = error as? APIError, let awsResponse = response as? AWSHTTPURLResponse, let responseBody = awsResponse.body { print("StatusCode: \(statusCode) Response Body: \(String(decoding: responseBody, as: UTF8.self))") } }}
await addToGroup(username: "richard", groupName: "Editors")- グループ内のユーザーを一覧表示するには、以下を使用します。
func listEditors(groupName: String, limit: Int, nextToken: String? = nil) async { let path = "/listUsersInGroup" var query = [ "groupname": groupName, "limit": String(limit) ] if let nextToken = nextToken { query["token"] = nextToken }
let request = RESTRequest(path: path, queryParameters: query, body: nil) do { let data = try await Amplify.API.get(request: request) print("Response Body: \(String(decoding: data, as: UTF8.self))") } catch { if case let .httpStatusError(statusCode, response) = error as? APIError, let awsResponse = response as? AWSHTTPURLResponse, let responseBody = awsResponse.body { print("StatusCode: \(statusCode) Response Body: \(String(decoding: responseBody, as: UTF8.self))") } }}
await listEditors(groupName: "Editors", limit: 10)注:HostedUI を使用した Cognito ユーザープール
amplifyconfiguration.json の管理クエリ API 構成では、エンドポイントの認可タイプが AMAZON_COGNITO_USER_POOLS に設定されます。この認可タイプでは、Amplify.API はアクセストークンでリクエストを実行します。ただし、HostedUI を使用する場合、サインインしているにもかかわらず、アプリは許可されていない応答を受け取る場合があり、ID トークンの使用が必要になります。authorizationType を「NONE」に設定し、ID トークンを返すカスタムインターセプタを追加します。
{ "awsAPIPlugin": { "[YOUR-RESTENDPOINT-NAME]": { "endpointType": "REST", "endpoint": "[YOUR-REST-ENDPOINT]", "region": "[REGION]", "authorizationType": "NONE" } }}API にカスタムインターセプタを追加します
try Amplify.configure()try Amplify.API.add(interceptor: MyCustomInterceptor(), for: "[YOUR-RESTENDPOINT-NAME]")リクエストの ID トークンを返すようにカスタムインターセプタを設定します。
import Amplifyimport AWSPluginsCore
class MyCustomInterceptor: URLRequestInterceptor { func latestAuthToken() async throws -> String { guard let session = try await Amplify.Auth.fetchAuthSession() as? AuthCognitoTokensProvider else { throw AuthError.unknown("Could not retrieve Cognito token") }
let tokens = try session.getCognitoTokens().get() return tokens.idToken }
func intercept(_ request: URLRequest) async throws -> URLRequest { var request = request do { let token = try await latestAuthToken() request.setValue(token, forHTTPHeaderField: "authorization") } catch { throw APIError.operationError("Failed to retrieve Cognito UserPool token.", "", error) } return request }}管理アクションの追加
デフォルトには含まれていないが Amazon Cognito によって有効化されている追加の管理アクションを追加するには、生成された Lambda 関数コードを更新する必要があります。変更にはアクション用のルートハンドラーを追加し、それ用のルートを作成することが含まれます。その後、Express アプリ内のルートにルートハンドラーを関連付けます。
以下は、ユーザーの属性を更新できるようにする管理アクションを追加する方法の例です。
async function updateUserAttributes(username, attributes) { const params = { Username: username, UserAttributes: attributes, UserPoolId: 'STRING_VALUE', };
console.log(`Attempting to update ${username} attributes`);
try { await cognitoIdentityServiceProvider.adminUpdateUserAttributes(params).promise(); console.log(`Success updating ${username} attributes`); return { message: `Success updating ${username} attributes`, }; } catch (err) { console.log(err); throw err; }}ルートハンドラーが定義されたら、正しい HTTP メソッドを使用してルートを Express アプリに追加し、ルートハンドラーをルートに関連付けます。ルートが一意であることを確認してください。
以下は、/updateUserAttributes という名前の POST ルートを追加し、上記のルートハンドラーをそれに関連付ける方法の例です。
app.post('/updateUserAttributes', async (req, res, next) => { if (!req.body.username || !req.body.attributes) { const err = new Error('username and attributes are required'); err.statusCode = 400; return next(err); }
try { const response = await updateUserAttributes(req.body.username, req.body.attributes); res.status(200).json(response); } catch (err) { next(err); }});