AWS cognito を使って React SPA に認証機能を導入してみた

5 min read読了の目安(約5000字

今時の認証って🧐

現代はもう認証機能は自分で実装する時代では無さそうです。

この、「どのアプリでも一般的に使われているけど本質的な価値になっていない」類の作業を、かの AWS センセーは 「付加価値を生み出さない重労働」 と定義しました。
これらをなるべく削減して、エンジニアが本質的な顧客価値に直結する作業に注力できるようにするのというのがトレンドです。

せっかくReact で初めてのSPAを作ったので、ついでに前から気になっていた AWS cognito を使って認証機能を付けてみました。

ざっくりとした導入だけですが、基本的な使い方だけなら非常に簡単かつセキュアに実装できるのでは無いかと思います!!

以前作った SPA については記事にしています。 こちら 。 Rails API でバックエンドを実装した React SPA についてイメージを掴めるような内容になっていると思いますのでこちらもお願いします🙏
今回はこちらのアプリに認証を付けてみました。

リポジトリは公開しています🙌

https://github.com/tatsuro-m/react_rails_api_frontend_add_auth

至らない部分も多いと思いますのでご指摘頂ければと思います🏄‍♂️

実践

細かい部分についてはこちらの記事 が非常に参考になりますし、分かりやすいと思います。

基本的な流れとしては、

  1. サインアップ、サインイン、ログアウトなど必要そうなコンポーネントを作成する
  2. ルートコンポーネント(今回の場合なら App.js )に良い感じに組み込む

という感じになります。

AWS が提供している SDK を使うことによって、簡単に cognito の API を叩くことができます。
ここで叩くAPIというのは、ログイン、ログアウト、サインアップ、など一通りのものが揃っています。
その API に対して決められたフォーマットで、ユーザが画面から入力した email や password などを送信すればOKです!!

使用する SDK ですが、 Amplify 用のものです。その中の cognito 用の部分を利用する感じですね。

https://github.com/aws-amplify/amplify-js/tree/master/packages/amazon-cognito-identity-js

こちらを使うと非常に簡単に cognito のAPI にアクセスできます。

詳しくはリポジトリを参照頂ければと思いますが、まずは AWS 画面からユーザープール、アプリクライアント、そしてIDプールの設定を済ませます。

そうすると以下3つの認証情報が払い出されます。

  1. アプリクライアントID
  2. ユーザープールID
  3. アイデンティティプールID

こらら3つの情報を使います。

React アプリの src 配下にこれらの認証情報を書き込むファイルを用意します。

awsConfiguration.js
const awsConfiguration = {
  region: "ap-northeast-1",
  IdentityPoolId: "********",
  UserPoolId: "˜*******",
  ClientId: "*********",
};

export default awsConfiguration;

認証情報になりますので、必ず git 管理しないようにしましょう!!

.gitignore
src/awsConfiguration.js

あとは API を叩いて、その結果に応じて state を変更するなりすればOKです😁
一応イメージが湧きやすいように、サインアップの部分だけ書かせてください。

SignUp.js
//省略

  signUp() {
    const attributeList = [
      new CognitoUserAttribute({
        Name: "email",
        Value: this.state.email,
      }),
    ];
    this.userPool.signUp(
      this.state.email,
      this.state.password,
      attributeList,
      [],
      (err) => {
        if (err) {
          console.log(err);
          this.setState({ error: true });
          return;
        }
        this.setState({
          email: "",
          password: "",
          success: true,
        });
      }
    );
  }

//省略

この関数は、サインアップするためのコンポーネントからの抜粋です。
ユーザーが登録したい認証情報(今回なら email & pass)を入力して、サインアップボタンを押した時に起動する関数です。

this.userPool.signUp という関数を使っているのが分かります。
これが SDK が提供してくれているものです。名前からも分かる通り、サインアップの API を叩くための関数です。

userPool は先ほど設定した認証情報を使って作成するユーザープールのインスタンスです。

  get userPool() {
    return new CognitoUserPool({
      UserPoolId: awsConfiguration.UserPoolId,
      ClientId: awsConfiguration.ClientId,
    });
  }

CognitoUserPool (SDKが提供)に対してユーザープールIDとクライアントIDを渡してインスタンスを作成しています。
そのユーザープール対してサインアップを行っています。


ログインに成功した場合には、 App.js が保持しているログインしているかどうかの state を更新します。
コンポーネントのレンダリングは条件付きレンダーとして、ログインしていない場合にはサインインのコンポーネントを表示するようにしました。

  render() {
    if (this.state.currentUser) {
// ログイン時に表示したい画面
      } else {
        return (
          <div className="App">
            <SignIn onSuccess={this.handleSignInSuccess} />
          </div>
        );
// 略

state.currentUser は現在認証されているユーザーを取得する関数で初期化してあります。

currentUser: this.userPool.getCurrentUser()

こちらも SDK が提供してくれています。
これで画面をリロードしてもログイン時の画面が表示されます。

という感じでログインの有無によってレンダリングするコンポーネントを変更することができました🙌

おまけ

という感じでログインの有無を state で管理するコードを自分で実装したのですが、これは後に愚行だということが判明しました😅
AWS 様のご配慮により、こんなベタな使い方はもっと簡単に実装できるようになっていました。

こちら の記事を参考にさせて頂きました。

公式リポジトリ にも書いてありますが、
aws-amplify-react というReact 用の拡張ライブラリをも利用することができます。

UI用のライブラリも入れておくと幸せになれます。

$ npm install aws-amplify aws-amplify-react @aws-amplify/ui-react

これを使うと、ログイン時にだけアプリルートを表示したいという要件が、

import { withAuthenticator } from '@aws-amplify/ui-react';
export default withAuthenticator(App);

これだけで完成します🧐

withAuthenticator() でアプリルートをラップするだけです。
その他にも、ログアウトボタンなんかも用意されています。
今回は API を自力で叩きましたが、そんなことは不要なようです。

AmplifySignOut コンポーネントを使うだけです。

import { AmplifySignOut } from '@aws-amplify/ui-react';
<AmplifySignOut />

終了です。
ヤバババ。。。

ちなみにこういう機能はReact だけじゃなくて Vue でも利用できます。
フレームワークに合ったライブラリを入れればOKです。
ヤバババ。。。

こんな感じで、とにかく 「付加価値を生み出さない重労働」 を排除していくんだという決意が滲み出ております。
どんどん便利になっていくものですね!!

終わりに

認証機能を切り出すというのは最近流行ったものでは無いと思いますが、 cognito を使ったことが無いという方は非常に多いのでは無いでしょうか?
どんなアプリにも正解なわけでは無いですが(この辺はまた記事にしたい)、有力な選択肢なのは間違い無さそうです。

どなたかの参考になれば嬉しいです!!


参考にさせて頂いた資料