AmplifyのAuthメソッドをオーバーライドし、認証前後で処理を追加する

2022.06.30

こんにちは。データアナリティクス事業本部 サービスソリューション部の北川です。

今回は、Amplify Authenticatorの内部の仕組みがわからず、追加の処理を実装するのに苦労したので、共有したいと思います。

Amplify Authenticatorについて

AmplifyのAuthenticatorを使用することで、画面の実装含め、認証周りの処理をAmplify側に任せることができます。

import { Amplify } from 'aws-amplify';
import { Authenticator } from '@aws-amplify/ui-react';
import '@aws-amplify/ui-react/styles.css';
import awsExports from './aws-exports';
Amplify.configure(awsExports);

const Sample = () => {
  return (
    <Authenticator>
      {({ signOut, user }) => (
        // 認証後に表示するコンポーネント
      )}
    </Authenticator>
  );
}

export default Sample;

Authenticatorでラッピングするだけで、簡単に認証処理を実装してくれるので、開発効率が上がります。

Amplify Authメソッドのオーバーライド

Amplifyの認証実行時に、追加の処理が必要な場合は、関数をオーバーライドする必要があります。

Authメソッドを上書きする関数は、以下の種類があります。

  • handleSignUp
  • handleSignIn
  • handleConfirmSignIn
  • handleConfirmSignUp
  • handleForgotPassword
  • handleForgotPasswordSubmit

認証前に処理を追加

公式の例を見ると、ユーザー名とEメールを小文字に変換する処理を追加しています。

import { Amplify, Auth } from 'aws-amplify';
import { Authenticator } from '@aws-amplify/ui-react';
import '@aws-amplify/ui-react/styles.css';
import awsExports from './aws-exports';
Amplify.configure(awsExports);

export default function AuthenticatorWithEmail() {
  const services = {
    async handleSignUp(formData) {
      let { username, password, attributes } = formData;
      // custom username
      username = username.toLowerCase();
      attributes.email = attributes.email.toLowerCase();
      return Auth.signUp({
        username,
        password,
        attributes,
      });
    },
  };

  return (
    <Authenticator services={services} initialState="signUp">
      {({ signOut }) => <button onClick={signOut}>Sign out</button>}
    </Authenticator>
  );
}

この例では、認証が実行される前に処理を追加して、SignUp()をオーバーライドしています。

認証後に処理を追加

次に認証の実行後に追加する処理について実装します。

この時、上書きする前の関数(ライブラリ)が、本来望んでいた値を返す必要があります。

初期の戻り値

signInに処理を追加せずに、そのまま返す場合、戻り値はPromiseになっています。

戻り値を指定しない場合:

戻り値がPromiseとなり、本来望んでいた値を返していないため、不具合が生じます。

戻り値を指定した場合:

戻り値が本来望んでいた値(Promise)と一致しています。

基本的にtypeScriptではanyを避けたいので、実装例は以下のようになります。型を定義することで、戻り値を返さない場合にエラーを出してくれます。

import { Amplify, Auth } from 'aws-amplify';
import { Authenticator } from '@aws-amplify/ui-react';
import { CognitoUserAmplify } from '@aws-amplify/ui'
import '@aws-amplify/ui-react/styles.css';
import awsExports from './aws-exports';
Amplify.configure(awsExports);

type FormData = {
  username: string
  password: string
}

const Sample = () => {
  const services = {
    async handleSignIn(formData: FormData): Promise<CognitoUserAmplify> {
      const { username, password } = formData;

      return Auth.signIn({
        username,
        password,
      }).then((user) => {
        console.log('success');
        router.push('/');

        return user;
      })
    },
  }

  return (
    <Authenticator services={services} loginMechanisms={['email']}>
      {({ signOut }) => <button onClick={signOut}>Sign out</button>}
    </Authenticator>
  );
};

export default Sample;

認証が成功した時に、"/"に移動する処理を追加することができました。

もちろんオーバーライド機能によって、エラー時の処理についてもカスタマイズすることが可能です。ちなみにエラー構文を記述しなければ、(Amplifyに)元々備わっていたエラー構文を返します。

まとめ

今回は、Amplifyの認証時の処理をオーバーライドする関数を試してみました。関数のオーバーライドについて知識が浅く、開発時はチームのメンバーに助けてもらいながら、実装しました。また一つ知識が増えたので、ありがたいです。基本的な部分だと思いますが、自分と同じように苦戦している人の助けになればと思います。

ではまた。