Vue.js & TypeScript でNavigationGuardを実装する
こんにちは!kossyです!
さて、今回はVue.js & TypeScriptでのRouterGuardの実装手順をブログに残してみたいと思います。
なお、今回はRails APIモードでdevise_token_authを使ってtoken認証を行っていて、VueRouterの導入は済んでいることを前提として書かせていただきます。
環境
Vue.js 3.0.5
Vue CLI 4.5.9
node 14.15.0
npm 6.14.8
実装手順
まずはsrc/router/index.tsのルーティング定義にmeta情報を付与します。
export default [ { path: '/', name: 'home', component: Home, meta: { requiresAuth: true } } }
ルーとパスにmeta情報としてrequiresAuthを付与しています。
後に実装するguards.ts内でrequiresAuthがtrueの場合に処理を実行するために用います。
次に、src/router/guards.tsを作成します。
import { validateToken } from '@/api/auth' import { NavigationGuardNext, RouteLocationNormalized, RouteRecordNormalized } from 'vue-router' export const authorizeToken = (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => { if (to.matched.some((record: RouteRecordNormalized) => record.meta.requiresAuth)) { validateToken() .then(() => { next() }) .catch(() => { next({ path: '/login' }) }) } }
recordの中身はRouteRecordNormalizedインターフェイスとなっており、pathやnameやmetaといったプロパティが定義されています。
なので、record.meta.requiresAuthでroutes.tsの方で定義したmeta情報にアクセスできます。
requiresAuthがtrueの場合、validateToken関数を呼び出し、エラーなく処理されればnext関数を引数なしで呼び出し、
認証に失敗した場合等の事象があればログインページに遷移するようになっています。
validateToken関数の中身はこのような実装になっています。(あくまで例です。)
export const getAuthDataFromStorage = (): AuthHeaders => { return { 'access-token': localStorage.getItem('access-token'), client: localStorage.getItem('client'), expiry: localStorage.getItem('expiry'), uid: localStorage.getItem('uid'), 'Content-Type': 'application/json' } } export const setAuthDataFromResponse = (authData: AuthHeaders): void => { if (authData['access-token'] && authData.client && authData.uid && authData.expiry) { localStorage.setItem('access-token', authData['access-token']) localStorage.setItem('client', authData.client) localStorage.setItem('uid', authData.uid) localStorage.setItem('expiry', authData.expiry) } } export const removeAuthDataFromStorage = (): void => { localStorage.removeItem('access-token') localStorage.removeItem('client') localStorage.removeItem('uid') localStorage.removeItem('expiry') } export const validateToken = async () => { return await axios.get(process.env.VUE_APP_API_BASE + '/auth/validate_token', { headers: getAuthDataFromStorage() }) .then((response) => { setAuthDataFromResponse(response.headers) return response.data }) .catch(() => { removeAuthDataFromStorage() }) }
トークンの有効性を検証するURLにリクエストを送って、トークンが有効であればユーザー情報を返却されます。
認証に失敗した場合はLocalStorageからトークンを削除します。
次に、index.tsを編集します。
import { authorizeToken } from './guards' // 省略 router.beforeEach(authorizeToken)
routerインスタンスのbeforeEach関数の引数に、先ほど定義したauthorizeToken関数を渡すと、ページ遷移が発生するたびにauthorizeToken関数が呼び出されるようになります。
勉強になりました。