Django

Django Vuejs JWT認証の実装を開始(Total:3day12.5h)

フロントエンド側にJWT用の共通処理を作成

きのうからの続きで、Vuejsからバックエンドにリクエストするときに、TokenをHeaderにつけて送る。Tokenが切れている場合は、RfreshTokenをHeaderにつけて再取得をする。って感じの実装をしたいと思ってる…


Serviceフォルダの中に共通処理用ファイルの作成

共通処理なので、srcフォルダの直下にserviceフォルダに、api.tsファイルを作成する。

ここまでは、簡単…それやぁ、フォルダを作成してからのファイルを作成しただけですもんね(笑)

ここからが格闘である💦

import axios from 'axios'

// リクエストするURLとタイムアウトとヘッダーJson形式であること
const api = axios.create({
    baseURL: process.env.Vue_APP_ROUTE_API,
    timeout: 6000,
    headers: {
        "Content-Type": "application/json",
        "X-Requested-With": "XMLHttpRequest"
    }
})

//リクエスト処理の前に処理を行う
api.interceptors.request.use(
    async (config) => {
        // Tokenがあればリクエストヘッダに追加
        const token = localStorage.getItem("access-token")
        if (token) {
            config.headers.['Authorization'] = "JWT" + token
            return config
        }
        return config
    },
    // エラー処理
    (error) => {
        return Promise.reject(error)
    }
)

リクエストを送る前に必ず、ローカルストレージにあるアクセストークンを取得して、ヘッダに付けて送るという処理を書きました!

多分、かけてると思う。動作確認ができてないからわからないけど…知らんけど(笑)

アクセストークンをリクエスト送信後エラーとなった場合の処理

アクセストークンを送信して、認証がエラーとなった場合、リフレッシュトークンで再取得に行い、取得できない場合はエラーとするようなイメージです。

途中まで書いてるけど動作確認もしてないし、Vuexを全く実装していないのであっているかチョー不安…

途中の状態だけど記載

// 共通処理
const refreshTokenPromise = null

api.interceptors.response.use(
    response => {
        return response
    },
    // エラー処理
    error => {
        console.log(error)
        // error statusがなければ500セット
        const status = error.response ? error.responose.status: 500
        const refreshToken = localStorage.getItem('refresh-token')
        // リフレッシュトークンがあるなら
        if (error.config && error.response && error.response.status === 401 && refreshToken && !error.config._retry) {
            //認証エラー
            if (!refreshTokenPromise) {
                //retryをtureに変更
                error.config._retry = true
                refreshTokenPromise = getRefeshToken().then(token => {
                    refreshTokenPromise = null
                    return token
                })
            }
            return refreshTokenPromise.then(token => {
                error.config.headers['refresh-token'] = token
                return 
            })
        }
    }
)

const getRefeshToken = () => {
    // refreshTokeで再取得挑戦
    try {
        const response = await axios.post(
            `${process.env.Vue_APP_ROUTE_API}api/token/refresh/`,
            {
                refresh: localStorage.getItem('refresh-token')
            },
            api.defaults.headers.common {
                'Authorization'
            }
        )
    
    }
}
export default api

うーん、なんかようわからん…
とりあえず最初のTokenをヘッダーにつけて送信する。が、ちゃんと動くのかもわからない…

Vuexで状態管理をしていく予定だし、リフレッシュトークンでの再取得を先に書き始めたけど、最初が正しく動いてるかもわからにうちに、すすむのを一度やめようと思う。

SPAじゃなかったらログイン認証はDjangoで数分で実装できるから、本当に大変だ💦

Vuex で状態管理するを学ぶ

Vuexは、各コンポーネントで扱う共通のデータを管理するためのものです。

https://next.vuex.vuejs.org/ja/guide/typescript-support.html

ユーザー認証情報は、どのリクエストでも使用するので、ログイン状態を管理することにとても向いています。

この動作を理解できれば、今後Vuexを利用するときに役に立ちそうです!

import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators';
import api from "@/common/api"


// グローバルな名前空間を使用
@Module({ namespace: true })
class User extends VuexModule {
    public isLoggedIn= false
    public username= ""

    @Mutation
    // ログイン認証成功時  voidで返り値のないメソッド
    public loginSucess(username: string): void {
        this.isLoggedIn = true
        this.username = username
    }

    @Mutation
    // ログイン認証失敗
    public loginFailure(): void {
        this.isLoggedIn = false
        this.username = ""

ここまでコードを書いてきましたが、何をどこのファイルだ実行することがいいのか、まだ、わかっていないところがある…

役割毎にファイルやフォルダを分ける方法がわからない
整理にもなれが必要

リフレッシュトークンの処理なしで動作確認しよう!

今、コードを書いてても動作確認してないので、これで動くかどうかが不明…
このまま進めるより、テストもかねて細かく動かしながら進めたい…でもどうやったら今のが動くかも、ちょっとわからない(笑)

今日は、3.5時間やってきましたが、Vuexについて、Stateで設定している状態をMutation(いちよ関数?)とActionで変更するというサイクルが何となく理解できたこと。

項目名概要
stateStore で管理するデータ項目を定義する
gettersstate データ状態から算出される値(≒算出プロパティ)
mutationsstate のデータを変更するための関数
actionsmutations を各コンポーネントから呼び出して変更するための関数

こんな感じなのかな。

なので、変更パターン分だけMutationは用意する必要があるってことだと…

ごろう
まだまだ、ログイン機能の完了までの道筋が見えてない!終わった時の感動がすごそう!

-Django

© 2022 ごろう@縁紡ぐ