Edited at

Vue.js 2.0 でログイン (vue-router で認証が必要な URL を定義)

認証が必要な URL にアクセスした時に、まだログインしていない場合にはログインボタンを表示します。

作成にあたって以下の知識が必要になるので、順に試していきます。


  • コンポーネント

  • vue-router

  • ルートメタフィールド、ナビゲーションガード

Playground として http://codepen.io を使用します。できあがったコードは http://codepen.io/takatama/pen/zoNeWP です。

Vue.js 2.0.7 と vue-router 2.0.2 で動作を確認しました。

なお、Vue.jsについて体系的に学ぶには「Vue.js入門」が超絶オススメです。ログイン、ログアウトについても丁寧に解説されています。


コンポーネント

ドキュメントは https://vuejs.org/v2/guide/components.html です。

User コンポーネントを作ります。プロパティとして name を持ちます。

codepen で Settings > JavaScript > Add External JavaScript で https://unpkg.com/vue/dist/vue.js と入力し、Save & Change ボタンを押します。

HTML:

<div id="app">

<About />
</div>

JavaScript:

var About = { template: '<h1>About</h1>' };

var app = new Vue({
el: '#app',
components: {
'About': About
},
});


vue-router

ドキュメントは http://router.vuejs.org/ja/essentials/getting-started.html です。

Dashboard コンポーネントを追加します。/about に About コンポーネント、/dashboard に Dashboard コンポーネントをそれぞれ登録します。

Settings > JavaScript > Add External JavaScript で

https://unpkg.com/vue-router/dist/vue-router.js を追加入力し、Save & Change ボタンを押します。

HTML:

<div id="app">

<p>
<router-link to="/about">About</router-link>
<router-link to="/dashboard">Dashboard</router-link>
</p>
<router-view></router-view>
</div>

JavaScript:

var About = { template: '<h1>About</h1>' };

var Dashboard = { template: '<h1>Dashboard</h1>' };

var routes = [
{ path: '/about', component: About },
{ path: '/dashboard', component: Dashboard }
];

var router = new VueRouter({
routes
});

var app = new Vue({
el: '#app',
router
});

<router-view>\ に選択されたコンポーネントが表示されます。


ログインページ

ドキュメントは

です。

/about は認証不要、/dashboard は認証が必要な URL とします。認証が必要な URL にアクセスし、かつ、まだログインしていない場合にログインボタンを表示します。

HTML (変更なし) :

<div id="app">

<p>
<router-link to="/about">About</router-link>
<router-link to="/dashboard">Dashboard</router-link>
</p>
<router-view></router-view>
</div>

JavaScript:

認証処理をする Auth と、Login コンポーネントを追加する。/login に Login コンポーネントを登録します。

/dashboard がログインを要することを meta で定義します。ナビゲーションガード router.beforeEach を使って、ログインが必要で、かつ、未ログインの場合に /login にリダイレクトします。

/login にリダイレクトする際、もともとアクセスしようとしていた URL を query パラメーターに付与します( /login?redirect=/dashbaord )。

var About = { template: '<h1>About</div>' };

var Dashboard = { template: '<h1>Dashboard</h1>' };

var Auth = {
loggedIn: false,
login: function() { this.loggedIn = true },
logout: function() { this.loggedIn = false }
};

var Login = {
template: '<input type="submit" value="Login" v-on:click="login">',
methods: {
login: function() {
Auth.login();
router.push(this.$route.query.redirect);
}
}
};

var routes = [
{ path: '/about', component: About },
{ path: '/dashboard', component: Dashboard, meta: { requiresAuth: true }},
{ path: '/login', component: Login }
];

var router = new VueRouter({
routes
});

router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth) && !Auth.loggedIn) {
next({ path: '/login', query: { redirect: to.fullPath }});
} else {
next();
}
});

var app = new Vue({
el: '#app',
router
});


ログアウト

Dashboard コンポーネントに /logout へのリンクを追加します。

JavaScript (主な差分のみ):

var Dashboard = {

template: '<div><h1>Dashboard</h1><router-link to="/logout">Logout</router-link></div>'
};

var Logout = {

template: '<input type="submit" value="Logout" v-on:click="logout">',
methods: {
logout: function() {
Auth.logout();
router.push('/');
}
}
};

var routes = [

{ path: '/about', component: About },
{ path: '/dashboard', component: Dashboard, meta: { requiresAuth: true }},
{ path: '/login', component: Login },
{ path: '/logout', component: Logout }
];


補足 (デフォルトで認証を有効にする)

ほとんどの URL で認証を必要とするのであれば、デフォルトで認証を有効にして、認証が不要な URL にだけ isPublic: true を指定する方が安全です。認証が必要な URL に meta を定義し忘れ、誤って一般公開してしまうミスを防ぐことができます。

// 全てのURLで認証を必要とする。isPubilc: true の場合だけ認証不要。

var routes = [
{ path: '/about', component: About, meta: { isPublic: true } },
{ path: '/dashboard', component: Dashboard}, // 認証を必要とする
{ path: '/login', component: Login, meta: { isPublic: true } }
];

var router = new VueRouter({
routes
});

router.beforeEach((to, from, next) => {
// isPublic でない場合(=認証が必要な場合)、かつ、ログインしていない場合
if (to.matched.some(record => !record.meta.isPublic) && !Auth.loggedIn) {
next({ path: '/login', query: { redirect: to.fullPath }});
} else {
next();
}
});