AWS Amplify Gen 2 でユーザープールのカスタム属性を設定し、標準サインアップ画面で使用してみた
いわさです。
マルチテナントっぽい Web アプリケーションのプロトタイプを Amplify Gen 2 で作成しています。
Amplify Gen 2 のデフォルト認証プロバイダーは Cognito ユーザープールが使われるわけですが、マルチテナントのプール型で作成するのであればユーザープールのカスタム属性としてテナントコンテキストは最低限設定しておきたいところです。
今回は Amplify Gen 2 の Auth コンポーネントからカスタム属性を設定してみたのですが、ちょっとエラーが発生したので解決方法などもまとめておきたいと思います。
カスタム属性の設定方法
まず、カスタム属性の設定方法自体は公式ドキュメントでも紹介されており、そのとおり対応するだけです。
defineAuth 内で認証に関する構成を定義出来るのですが、userAttributes
プロパティを指定することで追加の属性を指定出来ます。
Cognito 標準属性が指定出来るのですが、文字列で指定することでカスタム属性も指定出来ます。注意点としてはプレフィックスがcustom:
である点です。これはまぁ Cognito の仕様なのであまり違和感はないです。
次のようにカスタム属性を定義してみました。
import { defineAuth } from '@aws-amplify/backend';
import { preSignUp } from './pre-sign-up/resource';
/**
* Define and configure your auth resource
* @see https://docs.amplify.aws/gen2/build-a-backend/auth
*/
export const auth = defineAuth({
loginWith: {
email: true,
},
triggers: {
preSignUp
},
userAttributes: {
"custom:tenant_id": {
dataType: "String",
mutable: true,
},
},
});
does not exist in type 'StandardAttributes' エラーが発生
ここで問題が発生しまして、サンドボックス環境のバックエンドリソースをデプロイしようとしたところ次のエラーが発生してデプロイに失敗しました。
% npx ampx sandbox
[Sandbox] Pattern !.vscode/extensions.json found in .gitignore. ".vscode/extensions.json" will not be watched if other patterns in .gitignore are excluding it.
Amplify Sandbox
Identifier: iwasa.takahito
Stack: amplify-amplifyvitereacttemplate-iwasatakahito-sandbox-c16ed1c1a8
To specify a different sandbox identifier, use --identifier
amplify/auth/resource.ts(16,5): error TS2353: Object literal may only specify known properties, and '"custom:tenant_id"' does not exist in type 'StandardAttributes'.
TypeScript validation check failed.
Resolution: Fix the syntax and type errors in your backend definition.
[Sandbox] Watching for file changes...
StandardAttributes しか設定できないような気がします。
参照モジュールの中身を見てみても次のような感じ。なんだかドキュメントの記載のとおり文字列を指定出来るようには見えないです。
しかし、Amplify Backend の GitHub リポジトリを確認してみたところ、リモートリポジトリでは別の型になってます。なんか指定出来そうだな...
更新履歴を確認したところ、このカスタム属性を設定出来るようにする機能は 7 月 17 日にマージされたばかりの機能でした。
で、今使っているプロジェクトは公式ドキュメントの Quickstart を元にテンプレートから作成したものです。
そのため package.json で参照されているパッケージが古かったようです。なるほど。
% npm outdated
Package Current Wanted Latest Location Depended by
@aws-amplify/backend 1.0.4 1.1.1 1.1.1 node_modules/@aws-amplify/backend hoge0817amplify
@aws-amplify/backend-cli 1.1.1 1.2.4 1.2.4 node_modules/@aws-amplify/backend-cli hoge0817amplify
@aws-amplify/ui-react 6.1.13 6.2.0 6.2.0 node_modules/@aws-amplify/ui-react hoge0817amplify
@types/react 18.3.3 18.3.4 18.3.4 node_modules/@types/react hoge0817amplify
@typescript-eslint/eslint-plugin 7.16.1 7.18.0 8.2.0 node_modules/@typescript-eslint/eslint-plugin hoge0817amplify
@typescript-eslint/parser 7.16.1 7.18.0 8.2.0 node_modules/@typescript-eslint/parser hoge0817amplify
aws-amplify 6.5.1 6.5.2 6.5.2 node_modules/aws-amplify hoge0817amplify
aws-cdk 2.149.0 2.154.0 2.154.0 node_modules/aws-cdk hoge0817amplify
aws-cdk-lib 2.149.0 2.154.0 2.154.0 node_modules/aws-cdk-lib hoge0817amplify
:
パッケージのバージョンアップを行いました。
{
"name": "amplify-vite-react-template",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@aws-amplify/ui-react": "^6.2.0",
"aws-amplify": "^6.5.2",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@aws-amplify/backend": "^1.1.1",
"@aws-amplify/backend-cli": "^1.2.4",
"@types/aws-lambda": "^8.10.143",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@vitejs/plugin-react": "^4.2.1",
"aws-cdk": "^2.138.0",
"aws-cdk-lib": "^2.138.0",
"constructs": "^10.3.0",
"esbuild": "^0.20.2",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"tsx": "^4.7.2",
"typescript": "^5.4.5",
"vite": "^5.2.0"
}
}
バージョンアップ後はサンドボックスのバックエンドデプロイに成功し、作成された Cognito ユーザープールを見てみると、無事カスタム属性が定義されています。良いですね。
サインアップ画面をカスタマイズする
で、テナント情報を属性として設定出来るようになったのでユーザーに指定したいところです。
ユーザーに入力させるか、あるいはカスタムトリガーで自動でテナントを識別して設定する方法が考えられます。
今回は簡単にユーザー入力させてみようかなと思いますので、標準のサインアップ画面をカスタマイズしましょう。
テンプレートの場合はApp.tsx
でAuthenticator
コンポーネントが使われています。
:
return (
<Authenticator>
{({ signOut }) => (
<main>
<h1>My Hoges</h1>
<button onClick={createHoge}>+ new</button>
<ul>
{hoges.map((hoge) => (
<li key={hoge.id}>{hoge.HogeContent}</li>
))}
</ul>
<div>
🥳 App successfully hosted. Try creating a new Hoge.
<br />
<a href="https://docs.amplify.aws/react/start/quickstart/#make-frontend-updates">
Review next step of this tutorial.
</a>
</div>
<button onClick={signOut}>Sign out</button>
</main>
)}
</Authenticator>
);
}
このコンポーネントですが、カスタマイズ出来るようにいくつかスロットが用意されています。
次の公式ドキュメントを参照しましょう。
formFields
を設定してやることでカスタム属性を入力出来るようにしました。
フィールド名をカスタム属性名と一致させることでそのままデータ送信先として接続もされるようです。これは簡単だ。
:
const formFields = {
signUp: {
"custom:tenant_id": {
label: 'Hoge Tenant',
order: 1
}
}
};
return (
<Authenticator formFields={formFields}>
{({ signOut }) => (
<main>
<h1>My Hoges</h1>
<button onClick={createHoge}>+ new</button>
<ul>
{hoges.map((hoge) => (
<li key={hoge.id}>{hoge.HogeContent}</li>
))}
</ul>
<div>
🥳 App successfully hosted. Try creating a new Hoge.
<br />
<a href="https://docs.amplify.aws/react/start/quickstart/#make-frontend-updates">
Review next step of this tutorial.
</a>
</div>
<button onClick={signOut}>Sign out</button>
</main>
)}
</Authenticator>
);
}
export default App;
上記設定にて次のようなフォームが作成されました。良いですね。
登録もしてみましょう。
ユーザープールのカスタム属性に無事設定されていました。
さいごに
本日は AWS Amplify Gen 2 でユーザープールのカスタム属性を設定し、標準サインアップ画面で使用してみました。
Quickstart のテンプレートから開始している場合などもそうですが、開発環境のパッケージのバージョンアップを怠っているとドキュメントどおりいかなくなることを学びました。
標準コンポーネントも色々とカスタマイズ方法が提供されているのでなかなか良い感じです。
テナントの設定がとりあえず出来るようになったので、次回はこれを使ったデータ分離あたりを行ってみたいと思います。