KJ DEV
How to

Vueでアクセス制限をかけるコンポーネントを実装

Vueで実装しているページにアクセス制限をかけたくなったことはありませんか?

閲覧するのにユーザーの権限が必要なページ、非公開コンテンツのページなど通常見せてはいけないページにアクセスされた場合は何らかの対応が必要ですね。

エラー画面に遷移させる、違うコンテンツを表示するなど画面にアクセスしたときに特定の処理を挟むためにはどうすればいいのか。

今回はVueでそんな場合のアクセス制限をかける方法を紹介します。

目次
  1. slotを使う方法
    1. アクセス可能時とコンテンツを出し分ける
    2. アクセス不可能な場合にリダイレクトする
  2. Functionalオプションを使う方法
    1. render関数を使ってアクセス制限するメリット
    2. TypeScriptを使う場合はVNodeをreturnする
  3. まとめ

slotを使う方法

まずはslotを使いアクセスに可能な場合にはv-ifをtrueにすることで要素を表示できるようにする方法です。

アクセス判定に必要なpropsを受け取り、アクセス可能かどうかcomputedで返しています。
computedの値はslotを囲うdivにつけて内容が見えないようにします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
  <div v-if="isPermit">
    <slot/>
  </div>
</template>

<script>
export default {
  props: {
    example: {
      // サンプル用のprops
      type: Object
    }
  },
  computed: {
    isPermit() {
      return false;
    }
  }
};
</script>

この方法はslotを囲むためのdivが必要になります。

ほとんどのアプリケーションでは問題ないと思いますが、もしもdivが増えるのが困る場合は後に紹介するFunctionalオプションを使う方法を試してみてください。

アクセス可能時とコンテンツを出し分ける

もしアクセス可能ではない場合にはv-ifで出し分けます。

アクセス許可されていない場合はslotのコンテンツではなく独自のコンテンツを表示することで、ユーザーに状態を伝えることができます。

1
2
3
4
5
6
7
8
9
10
<template>
  <div>
    <div v-if="isPermit">
      <slot/>
    </div>
    <div v-if="!isPermit">
      コンテンツにアクセスする権限がありません。
    </div>
  </div>
</template>

アクセス不可能な場合にリダイレクトする

場合によってはコンテンツを表示しない、違うコンテンツを表示する以外にもリダイレクトしたいという場合もあると思います。

その時はmountedでアクセス許可されていない場合にlocationやvue-routerを使っている場合は$routerを使って任意のURLに遷移させます。

1
2
3
4
5
mounted() {
    if (!this.isPermit) {
      location.href = 'リダイレクト先'
    }
}

Functionalオプションを使う方法

Vueではtemplateタグを使ってテンプレートを記述するのが一般的ですが、render関数を使ってjsxのように記述できます。

functionalコンポーネントについて説明すると、長くなってしまうので今回は詳細な説明はしません。

もし気になる人はvueの公式ドキュメントを見てみてください。

https://jp.vuejs.org/v2/guide/render-function.html

render関数を使ってアクセス制限するメリット

vueの一般的な記述であるslotを使ってアクセス制限できるなら、わざわざrender関数を使う必要はないんじゃないのか?と思います。

ですがrender関数を使うと嬉しいメリットがあります。

それは余計なdivで囲む必要がなくなるということです。

まずはrender関数を使ってアクセス制限するコードは下記です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script>
export default {
  functional: true,
  props: {
    example: {
      // サンプル用のprops
      type: Object
    }
  },
  render(h, context) {
    // context.propsを使いアクセス可能か判定
    if (true) {
      return context.children;
    } else {
      // アクセスを弾く処理
    }
  }
};
</script>

rebder内のcontext.childrenがtemplateで言うところのslotのようなものです。
Reactをやったことある人はchildrenは馴染みがあるかもしれません。

context.childrenをrenderでreturnすることでtemplateではできなかったslotのあたる部分だけをレンダリングできるようになっています。

TypeScriptを使う場合はVNodeをreturnする

TypeScriptでのrender関数の返り値はVNodeです。(VNode[]も可能)

ですがrender内でリダイレクトしようとした場合には型ではundefinedが返却されることになります。

その際にコンパイルエラーが発生してしまうので、リダイレクト後に空のdivを返却することで回避できます。

1
2
3
4
5
6
7
8
render(h, context): VNode[] | VNode {
    if (true) {
      return context.children;
    } else {
      location.href = 'リダイレクト先'
      return h('div')
    }
}

location.hrefなどリダイレクト処理の後に```h('div')```というのが空divを生成するコードです。

まとめ

Vueでアクセス制限をかける方法を紹介しました。

アプリケーションを実装する中でアクセス制限をかけたい機会は少なくないと思います。

今回紹介した方法をベースに実装をするとコンテンツの出し分けやリダイレクトなど、アクセスを許可しない場合の処理も動作させることができます。

開発で参考になった本

実際に読んでみて開発に役立った本を紹介しています。

これから本格的にデザインシステムを学んで作りたい時にとても参考になる一冊でした。デザインシステムついて幅広く触れられているけど、「tailwindを触ってデザインシステムに興味を持った」という人でも少しずつ取り入れやすいです。