Django

Django Vuejs JWT認証の実装(Total:5day21h)

Django側にserializerの設定を追加

プログラミングって概念や造りを理解できると、とっても早く開発がすすめれると思う。
問題は、概念や造りがたくさんあるのと、目に見えて分かりやすくないということだ…

フレームワークなんかを使っていると裏で何をしてくれてるのかがわからない。でも、それでいいんだーそれまで習得しようと思ったら、もっと時間がかかってしまうから。

settings.py シリアライザーのJWTの設定を少し変更

ログイン認証はできているけど、そのあと、Djangoniデータ取得をリクエストしてもエラーになってしまいます。

user.modelにJWTTokenなんて見つからないよーって感じで、自動で作成されるのでは思って色々調べたんですが、そうではなく、Settingファイルの設定の問題でした(笑)

これだけでも30分ははまりました💦

SIMPLE_JWT = {
    # アクセストークンの有効時間
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
    # 更新トークンの有効期間
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    # リフレッシュトークンがされるか
    'ROTATE_REFRESH_TOKENS': True,
    # ブラックリストに追加
    'BLACKLIST_AFTER_ROTATION': True,
    # ログイン時に更新しない 遅延対策
    'UPDATE_LAST_LOGIN': False,

    # 暗号化方式
    'ALGORITHM': 'HS256',
    # 生成されたトークンに署名キー Djangoのキーはおすすめしない
    'SIGNING_KEY': env('TOKEN_KEY'),
    # 生成されたトークンの内容を検証
    'VERIFYING_KEY': None,
    'AUDIENCE': None,
    'ISSUER': None,
    'JWK_URL': None,
    # 有効期限
    'LEEWAY': 0,

    # 認証が必要で受け入れられる許可ヘッダータイプ
    'AUTH_HEADER_TYPES': ('JWT',),
    # 認証に使用される許可ヘッダー
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    'USER_ID_FIELD': 'id', #修正
    'USER_ID_CLAIM': 'username', #修正
    # ユーザーが認証を許可されているかどうかを判断する
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',

    # 認証を証明できるトークンタイプ
    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), #修正
    # トークンのタイプを格納する名
    'TOKEN_TYPE_CLAIM': 'token_type',
}

usersにviewsフォルダを作成してusers.pyファイルを作成

urls.pyから呼び出しをされるViewを作成。

rest_framework.genericsには、さまざまなAPIを用意してくれているので覚えていくと色んな事ができるようになりそう!

あんなことやこんなことができたらいいなぁー

from rest_framework.generics import RetrieveAPIView, ListAPIView
from users.models import User
from ..serializers.users import *

class UserInfoAPIView(ListAPIView):
    """
    Args:
        ListAPIView (): []

    Returns:
        [object]: [ログインユーザー情報]]
    """
    queryset = User.objects.all()
    serializer_class = UserDetailSerializer
    
    def get_object(self):
        return self.request.user

ここで、クエリセットで取得したデータをこのシリアライザーで変換してね!って、お願いするって感じですね(⌒∇⌒)

serializersフォルダを作成しusers用シリアライザーファイルを作成

上のViewから呼び出されてお願いされるシリアライザーを作成します。

from rest_framework import serializers
from users.models import User

class UserDetailSerializer(serializers.ModelSerializer):
    """
    ユーザー詳細シリアライザー
    """
    class Meta:
        model = User
        fields = [
            'username',
            'first_name',
            'last_name',
            'get_full_name',
        ]

便利なことは、modelsに書いてある関数も実行できることです。
ここでいえば、get_full_nameでfirst_nameとlast_namがくっついた値を取得できます

実際にDjangoからデータがかえってくるか試してみましょう

ちゃんと、情報がかえってきています✊
お待たせしました!いや、待たせすぎたかもしれません(笑)

苦節、約20時間…まだ、ログイン機能としては、中途半端な状態かもしれませんが、動くことには間違いありません!
こうやって、少しの進歩を最大限、自分なりに感じて『成長してるー!』って、思うようにしよっと

ログイン認証を失敗した場合の処理

ログインする時には、必須の対応ですね!誰しも間違えることはあるので間違えてるよーっていう処理を入れようと思う。
こちらのライブラリをインストールして、見た目よく実装をおこなっていきます。

vue-sweetalert2 をインストール

https://www.npmjs.com/package/vue-sweetalert2

npm install -S vue-sweetalert2

公式サイトに書いてある通り、main.tsに追記をします。

import Vue from "vue";
import App from "./App.vue";
import "./registerServiceWorker";
import router from "./router";
import store from "./store";
import vuetify from "./plugins/vuetify";
import VueSweetalert2 from 'vue-sweetalert2';
import 'sweetalert2/dist/sweetalert2.min.css';

Vue.config.productionTip = false;
Vue.use(VueSweetalert2);

new Vue({
  router,
  store,
  vuetify,
  render: (h) => h(App),
}).$mount("#app");

あとは、表示したい処理のところで$swalで呼び出すだけでOK。
便利な世の中に乾杯🥂

ログインが成功した時には、Hello Vue World を出力し、失敗した時には、UsernameかPasswordに誤りがあります。と表示する。

    submitLogin() {
        this.$store
        .dispatch("authen/login", {
            username: this.username,
            password: this.password
        })
        .then(() => {
            console.log("login成功")
            this.$swal('Hello Vue world!!!');
        })
        .catch(() => {
            this.$swal('UsernameかPasswordに誤りがあります。')
        })
    }

実際にやってみましょう!

ログイン成功時の処理

ログイン失敗時

なんて素払い出来栄えでしょう!
素晴らしすぎて、見違えるようです(⌒∇⌒)

ポイント

ライブラリを使う時は人気のものを使おう!でないと、サポートが終わったりするからね

ログイン成功時にHome画面へ遷移

今は、ログイン成功してもログイン画面から変わらないのでなんか本当にログインできてるのかなって感じです(笑)
ログインしたら、Home画面へ遷移するように実装をおこないます。

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'

@Component({})
export default class Login extends Vue {
    username= null
    password= null
    showPassword= false

    submitLogin() {
        this.$store
        .dispatch("authen/login", {
            username: this.username,
            password: this.password
        })
        .then(() => {
            this.$router.push({ name: "Home" });
        })
        .catch(() => {
            this.$swal('UsernameかPasswordに誤りがあります。')
        })
    }
}
</script>

ここで、エラーが発生しました。
Routerに設定していた分岐が間違っていたので、修正

  if (!ToLoginPage) {
    if (!isLoggedIn){
      if (token != null) {
        store
        .dispatch("authen/renew")
        .then(() => {
          // 再取得
          next();
        })
        .catch(() => {
          // 取得できずログイン画面へ送還
          console.log('token取得失敗')
          forceToLoginPage(to)
        })
      } else {
        forceToLoginPage(to)
      }
    } else {
      //ログインしているよ    
      next()
    }
  } else {
    //ログインページだから関係なし
    console.log('ログインぺーじだよ')
    next()
  }
  next()
})

これで、ログインからHome画面へ遷移されるようになりました(⌒∇⌒)
あとは、リフレッシュトークンで再取得をどうするか考えたのですが、スマホでも操作する可能性があるので、安全のために再取得はやめにしました。

Home画面を変更する

Vuetifyには、テンプレートをあらかじめいくつか用意してくれています。

今回は、シンプルなデザインを利用します。

<template>
  <v-app id="inspire">
    <v-navigation-drawer
      v-model="drawer"
      app
    >
      <!--  -->
    </v-navigation-drawer>

    <v-app-bar app>
      <v-app-bar-nav-icon @click="drawer = !drawer"></v-app-bar-nav-icon>

      <v-toolbar-title>Application</v-toolbar-title>
    </v-app-bar>

    <v-main>
      <!--  -->
    </v-main>
  </v-app>
</template>

<script>
  export default {
    data: () => ({ drawer: null }),
  }
</script>

こんな感じで、作っていくようです。
Vueファイルも増えてくると大変そうなので整理するフォルダを考えながら作っていこうと思います!

-Django

© 2022 ごろう@縁紡ぐ