認証が必要な 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>\ に選択されたコンポーネントが表示されます。
ログインページ
ドキュメントは
- https://router.vuejs.org/ja/advanced/meta.html
- https://router.vuejs.org/ja/advanced/navigation-guards.html
です。
/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();
}
});