TL;DR
- aws-amplify-react の Auth モジュールが提供する
<SignUp>
は電話番号が必須になっている。 - これを無効にするには自分で専用の
<CustomSignUp>
を作る必要がある。- awsmobile-cli で生成した aws-exports.js から自動的に UI を変更してくれたりはしない。
- ドキュメントだけだとどう実装すればいいのか分からないので、ソースコードを見る必要がある
背景: 電話番号を無効にしたい
awsmobile-cli を使って作った AWS Mobile Hub プロジェクトに AWS Cognito を使った認証機能を追加することにしました。 CLI から User Pool を作って、 aws-amplify-react の withAuthenticator
HOC を使ってみたところ、アカウント登録画面で電話番号が必須になっていました:
電話番号を省略しようとしてもバリデーションエラーが発生します:
awsmobile-cli から作った User Pool の設定を見るとたしかに「必須の属性」に「電話番号」があるので、改めて今度は「必須の属性」を「なし」で User Pool を作り直し、設定ファイル(aws-exports.js)を更新しましたが、依然としてフォームに電話番号の欄があり、必須のままでした。どうすれば電話番号の入力を無効にできるのでしょう?
aws-amplify-react はそこまで賢くない
aws-amplify は awsmobile-cli が生成する aws-exports.js という設定ファイルをそのまま読むことができます:
import Amplify from "aws-amplify"
// User Pool ID とかそういう情報が入っている。awsmobile-cli で自動生成される
import awsmobile from "./aws-exports"
Amplify.configure(awsmobile)
しかし、この aws-exports.js の中身をよくよく読んでみると、 User Pool ID などは書かれていますが、どういうものが必須かとかそういう情報は入っていません。
さらに悪いことに aws-amplify-react は awsmobile-cli でデフォルトで作られる User Pool に対応するようになっていて、登録時の項目を変更したかった場合は、自分でコードをたくさん書く必要があります。
カスタマイズする
ドキュメントによると withAuthenticator
は内部的に <Autheticator>
を使っており、こいつはさらに内部的に <SignIn>
などを使っていて、特定のビューを変更するにはそのコンポーネントを拡張したコンポーネントを渡せば良いようです。今回の場合は <SignUp>
を変更すれば良さそうです。残念ながら細かい部分はドキュメントが無いのでソースコードを見て空気を読んでやっていきます。
空気を読んで書いたコード
もとのファイルとの差分が分かりやすいように、削除したところをコメントアウトとして表現した。
import { Auth, I18n } from "aws-amplify"
import {
ButtonRow,
FormSection,
InputRow,
Link,
SectionBody,
SectionFooter,
SectionHeader,
SignUp,
} from "aws-amplify-react"
import * as React from "react"
export default class SignUpWithoutPhoneNumber extends SignUp {
showComponent(theme) {
const { hide } = this.props
if (hide && hide.includes(SignUp)) {
return null
}
return (
<FormSection theme={theme}>
<SectionHeader theme={theme}>{I18n.get("Sign Up Account")}</SectionHeader>
<SectionBody theme={theme}>
<InputRow
autoFocus={true}
placeholder={I18n.get("Username")}
theme={theme}
key="username"
name="username"
onChange={this.handleInputChange}
/>
<InputRow
placeholder={I18n.get("Password")}
theme={theme}
type="password"
key="password"
name="password"
onChange={this.handleInputChange}
/>
<InputRow
placeholder={I18n.get("Email")}
theme={theme}
key="email"
name="email"
onChange={this.handleInputChange}
/>
{/*<InputRow
placeholder={I18n.get('Phone Number')}
theme={theme}
key="phone_number"
name="phone_number"
onChange={this.handleInputChange}
/>*/}
<ButtonRow onClick={this.signUp} theme={theme}>
{I18n.get("Sign Up")}
</ButtonRow>
</SectionBody>
<SectionFooter theme={theme}>
<div style={theme.col6}>
<Link theme={theme} onClick={() => this.changeState("confirmSignUp")}>
{I18n.get("Confirm a Code")}
</Link>
</div>
<div style={Object.assign({ textAlign: "right" }, theme.col6)}>
<Link theme={theme} onClick={() => this.changeState("signIn")}>
{I18n.get("Sign In")}
</Link>
</div>
</SectionFooter>
</FormSection>
)
}
async signUp() {
const { username, password, email /*, phone_number */ } = this.inputs
try {
await Auth.signUp({
attributes: {
email,
// phone_number,
},
password,
username,
})
this.changeState("confirmSignUp", username)
} catch (err) {
this.error(err)
}
}
}
こうしてできた <SignUpWithoutPhoneNumber>
を withAuthenticator
の第三引数に渡します:
import {
ConfirmSignIn,
ConfirmSignUp,
ForgotPassword,
SignIn,
VerifyContact,
withAuthenticator,
} from "aws-amplify-react"
import * as React from "react"
import SignUpWithoutPhoneNumber from "./SignUpWithoutPhoneNumber"
class App extends React.Component {
// ...
}
export default withAuthenticator(App, false, [
<SignIn />,
<ConfirmSignIn />,
<VerifyContact />,
<SignUpWithoutPhoneNumber />, // ここ
<ConfirmSignUp />,
<ForgotPassword />,
])
これで無事に電話番号無しでアカウント作成できるようになった。