LoginSignup
21
23

More than 3 years have passed since last update.

Strapiに認証機能を追加する(特定のユーザしかAPIを呼べない仕様に変更する)

Last updated at Posted at 2020-01-17

Strapi APIに認証機能を追加してみる

前回の記事「Strapi (Headless CMS)を使ってみたので使い方まとめ + GraphQL」でHeadless CMS「Strapi」を使って簡易APIを作ってみました。
今回は特定のユーザしかAPIを呼び出せない様に、APIに認証を付けていきたいと思います。

ちなみに「公式サイト」に詳しく説明が載っているので、英語が読める方はこちらを読んで進めることを強くお勧めします。

この認証機能を使ったVueアプリのレポジトリーはこちらです
レポジトリ

事前知識

Strapiでは、「ロールと権限」というプラグインを使って認証を行います。(このプラグインは、デフォルトでインストールされいるはずです。)

このプラグインでは、「JSON Web Token (JWT)」を使い認証を行います。

JSON Web Tokenとは

JSON Web Token(JWT)とは、JSONというデータ構造で情報が表現されたフォーマットです。安全にデータを運ぶために使用されます。JWTの詳しい説明は、下記の記事がわかりやすいです。
JSON Web Token の効用
認証におけるJWTの利用について

ということで、StrapiはJWTを使って認証を行います。
APIリクエストが送信されると、サーバが「認証ヘッダーがあるか」と「ユーザからのリクエストは、リソースにアクセス可能なものか」を確認します。JWTにユーザIDが含まれているため、ユーザがどのグループに入っているか確かめることができます。結果としてリクエストされているルートにアクセスが可能かどうかの判断ができます。

ロールの種類

Strapiのロールには大きく分けて「public」と「authenticated」の2種類があります。それぞれのロールを説明していきます。

Public

「認証ヘッダ」がリクエストに含まれていない時に、このロールが使用されます。「全ての人」がこのロールに設定したエンドポイントにアクセス可能です。「find」や「findOne」などはこのpublicロールを使うといいと思います。

Authenticated

このロールでユーザがどのルートにアクセスできるかなど定義が可能です。ユーザを作成したときにデフォルトで付与されるのがこのロールです。

ユーザを作成する

Authenticatedのロールを持つユーザを作成してみます。

公式サイトにも書いてますが、基本的には下記のコードでユーザを作成できます。簡単!

import axios from 'axios';

axios
  .post('http://localhost:1337/auth/local/register', {
    username: 'Strapi user',
    email: 'user@strapi.io',
    password: 'strapiPassword',
  })
  .then(response => {
    // Handle success.
    console.log('Well done!');
    console.log('User profile', response.data.user);
    console.log('User token', response.data.jwt);
  })
  .catch(error => {
    // Handle error.
    console.log('An error occurred:', error);
  });

実装する

今回は私が練習用に作ったチェーン店メモアプリの「チェーン店めもったろう君」で上記の関数を実行してみます。(このアプリはVuetifyを使っているので、htmlタグはVeutify仕様になっています。)

「ユーザ登録」ボタンを押すと、usernameが「momoko1」のユーザがadminに登録されるはずです。
image.png

index.html
<v-row>
  <v-col cols="12" class="mt-4 d-flex justify-center">
    <v-btn 
    class="success"
    v-on:click="createUser"
    >
    ユーザ登録
    </v-btn>
  </v-col>
</v-row>
main.js

async createUser(){
  axios
  .post('http://localhost:1337/auth/local/register', {
    username: 'momoko1',
    email: 'momoko1@strapi.com',
    password: 'password',
  })
  .then(response => {
    console.log('Well done!');
    console.log('User profile', response.data.user);
    console.log('User token', response.data.jwt);
  })
  .catch(error => {
    console.log('An error occurred:', error);
  });
}

「ユーザ登録」ボタンを押すと、User profileとトークンが返ってきました。

image.png

strapiから「ロールと権限」→ Authenticatedにいくと・・・できてる!
image.png

このようにしてAuthenticatedのロールを持つユーザ作成ができます。

ログインしないとCRUD操作ができない様にする

それでは、ログインをしていないとチェーン店メモったろう君でチェーン店の登録も、データの取得もできない様にしていきます。

Authenticatedに権限を付与

まずは「ロールと権限」→ Publicから権限を全て外します。その次にAuthenticatedの権限で必要なCRUD操作にチェックを入れます。これでログインしていないユーザは何も操作ができない様になります。

image.png

image.png

実装する

index.html
<v-col>
  <v-form>
    <v-row
      justify="center"
    >
      <v-col
      cols="10"
      md="4"
      >
      <v-text-field
        v-model="email"
        label="Eメールアドレス"
      ></v-text-field>
      </v-col>
      <v-col
        cols="10"
        md="4"
      >
        <v-text-field
          v-model="password"
          label="パスワード"
        ></v-text-field>
      </v-col>
      <v-col
        md="1"
      >
        <v-btn 
          class="success"
          v-on:click="login"
          >
          ログイン
        </v-btn>
      </v-col>
    </v-row>
  </v-form>
</v-col>
main.js
async login() {
  axios
    .post('http://localhost:1337/auth/local', {
      identifier: this.email,
      password: this.password,
    })
    .then(response => {
      console.log('Well done!');
      console.log('User profile', response.data.user);
      console.log('User token', response.data.jwt);
    })
    .catch(error => {
      console.log('An error occurred:', error);
    });
}

先ほどのユーザ登録の際に使用したEメールアドレスとパスワードを使用してログインしてみます。ちなみに、identifierに入れるのはemailでもusernameでも良い様です。

Image from Gyazo

ログインが成功すると、こんな感じでUser Tokenがレスポンスとして返ってきます。
image.png

このトークンをリクエストヘッダに含めて認証を行い、認証が通ればCRUD操作ができる、という仕組みです。tokenという変数にresponse.data.jwtを格納する様にコードを修正します。

main.js
async login() {
  axios
  .post('https://powerful-dusk-72165.herokuapp.com/auth/local', {
    identifier: this.email,
    password: this.password,
  })
  .then(response => {
    this.token = response.data.jwt
    this.getRestaurants() // ログインが成功したらレストランデータをとる関数を動かす
  })
  .catch(error => {
    console.log('An error occurred:', error);
  });
},

あとは、

main.js
// 修正後
async getRestaurants(){
  try {
    var result = await axios({
      method: "POST",
      url: this.apiURL,
      headers: {
        Authorization: `Bearer ${this.token}`,
      },
      data: {
        query: `
          query getRestaurants {
            restaurants {
              id
              name
              description
            }
          }
        `
          }
      });
      this.restaurants = result.data.data.restaurants;
  } catch (error) {
    console.error(error);
  }
}   

// 修正前
async getRestaurants(){
  try {
    var result = await axios({
      method: "POST",
      url: this.apiURL,
      data: {
        query: `
          query getRestaurants {
            restaurants {
              id
              name
              description
            }
          }
        `
          }
      });
      this.restaurants = result.data.data.restaurants;
  } catch (error) {
    console.error(error);
  }
}    

できた!
Image from Gyazo

Strapiでユーザ認証をしてAPIを呼び出す方法でした。結構簡単でびっくり。SNSログインもできるみたいなので、また今度Qiita記事を書きながら試してみたいと思います。
公式サイトのドキュメントがとても丁寧なのもStrapiの魅力ですね。好きになっちゃいそう・・・。

21
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
23