# nuxtjs と codeigniter で jwt システム構築
laravel や lumen で api サーバー建てることが多く、今回バックエンドは codeigniter でやってみました。
構造
- フロントエンド nuxt2.11
- バックエンド codeigniter3.10
# codeigniter 側の設定
ユーザー認証でトークン発行して、その後トークンで認証とってデータやり取りする仕組み。バックとフロントが分離することで、サーバーサイドの仕事がシンプルになります。
# composer firebase php jwt 入れる
jwt 暗号化エンコードとデコード用に自前で作成することも一つの選択肢ですが、自前で作るより時間短縮できるし、バグ修正などの手間もなく、google 製で安心などのメリットがあって firebase のライブラリ使用
composer require firebase/php-jwt
使い方はシンプル
$jwt = JWT::encode($payload, $key);
$decoded = JWT::decode($jwt, $key, array('HS256'));print_r($decoded);
参考:firebase/php-jwt (opens new window)
Config 設定変更
application/config/config.php
// composer autoload
$config['composer_autoload'] = APPPATH . '../vendor/autoload.php';
// jwt 用エンクリプトキー設定
$config['encryption_key'] = 'abc123';
# MY_Controller 作成
MY_Controller 作成してグローバル関数や設定します。
application/core/MY_Controller.php
<?php
class MY_Controller extends CI_Controller
{
protected $post;
public function __construct()
{
parent::__construct();
// cors optionsリクエスト対策
if ($this->input->method() == 'options') {
return $this->json([]);
}
// json リクエスト array post 変換
$this->post = $this->input->raw_input_stream ? json_decode($this->input->raw_input_stream) : null;
}
public function json(array $response, int $status = 200)
{
// json export
$this->output
->set_status_header($status)
->set_header('Access-Control-Allow-Origin: http://localhost:3000')
->set_header('Access-Control-Allow-Headers: *')
->set_header('Access-Control-Request-Method: POST,GET')
->set_content_type('application/json', 'utf-8')
->set_output(json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))
->_display();
exit;
}
}
Auth コントローラー
<?php
defined('BASEPATH') or exit('No direct script access allowed');
use \Firebase\JWT\JWT;
class Auth extends MY_Controller
{
public function login()
{
if (!$this->post) {
return $this->json(['result' => false]);
}
// テスト用トークン発行
$token = JWT::encode($this->post, $this->config->item('encryption_key'));
$response = ['result' => true, 'token' => $token];
$this->json($response);
}
public function logout(){
}
public function user()
{
$token = $this->input->get_request_header('Authorization', true);
// トークンでデータ返却
$response = ["user" => ["username" => "asdf", "picture" => "https://github.com/nuxt.png", "level" => 2]];
$this->json($response);
}
}
# おまけ:codeigniter index.php 省略
index.php を省略するための htaccess 設定
public/.htaccess の設定
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
#Removes access to the system folder by users.
#Additionally this will allow you to create a System.php controller,
#previously this would not have been possible.
#'system' can be replaced if you have renamed your system folder.
RewriteCond %{REQUEST_URI} ^system.*
RewriteRule ^(.*)$ /index.php?/$1 [L]
#When your application folder isn't in the system folder
#This snippet prevents user access to the application folder
#Submitted by: Fabdrol
#Rename 'application' to your applications folder name.
RewriteCond %{REQUEST_URI} ^application.*
RewriteRule ^(.*)$ /index.php?/$1 [L]
#Checks to see if the user is attempting to access a valid file,
#such as an image or css document, if this isn't true it sends the
#request to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>
<IfModule !mod_rewrite.c>
# If we don't have mod_rewrite installed, all 404's
# can be sent to index.php, and everything works as normal.
# Submitted by: ElliotHaughin
ErrorDocument 404 /index.php
</IfModule>
codeigniter のいいところはシンプルでわかりやすい、作業効率が上がるし、面倒な設定がない、ちょっとしたすぐに実現したいシステムならぴったり
# Nuxtjs 側 auth module 設定
nuxt の公式モジュール Auth Module @nuxtjs/auth を使います。@nuxtjs/auth は非常によくできている認証系モジュールです。このモジュール一つで通常のユーザー認証と google 認証 github facebook などはあっという間にできてしまうので、Auth Module 公式サイト (opens new window)確認するだけで使えます。
サポートしているプロバイダー
- Auth0
- Github
- Laravel Passport
# ログイン画面
ユーザー登録のタイミングで google ログイン github ログインなどしてもらって本登録するシステムなので、ログイン画面はローカル認証のみ
<template>
<b-card class="my-login">
<b-alert v-if="error" show variant="danger">{{ error + '' }}</b-alert>
<b-form-group label="Email" label-for="loginID" label-class="text-left">
<b-form-input id="loginID" v-model="email" type="email" class="bg-danger" required />
</b-form-group>
<b-form-group label="Password" label-for="loginPW" label-class="text-left">
<b-form-input id="loginPW" v-model="password" type="password" required />
</b-form-group>
<b-button
variant="warning"
:class="['d-block w-100 mt-5',{'animated shake':error}]"
@click.prevent="login"
>ログイン</b-button>
<!-- パスワードを忘れた場合 -->
<div class="mt-3 small a-divider-break"></div>
<div class="my-2 small">
新しいお客様ですか?
<n-link to="/register">アカウント作成</n-link>
</div>
<!-- <div class="my-2 small">
<n-link to="/register">パスワードを忘れた場合</n-link>
</div>-->
</b-card>
</template>
<script>
export default {
data() {
return {
email: null,
password: null,
error: null
};
},
methods: {
async login() {
this.error = null;
return this.$auth
.loginWith("local", {
data: {
email: this.email,
password: this.password
}
})
.catch(e => {
this.error = e + "";
});
}
}
};
</script>
<style lang="scss" scoped>
.my-login {
max-width: 320px;
width: 100%;
position: fixed;
left: 50%;
transform: translate(-50%, -50%);
bottom: 150px;
}
</style>
# nuxt.config.js 設定
modules: [
// Doc: https://bootstrap-vue.js.org
"bootstrap-vue/nuxt",
// Doc: https://axios.nuxtjs.org/usage
"@nuxtjs/axios",
"@nuxtjs/pwa",
// Doc: https://github.com/nuxt-community/dotenv-module
"@nuxtjs/dotenv",
"@nuxtjs/auth"
],
auth: {
strategies: {
local: {
endpoints: {
login: {
url: process.env.API_URL + "/auth/login",
method: "post",
properryName: "token"
},
logout: {
url: process.env.API_URL + "/auth/logout",
method: "post"
},
user: {
url: process.env.API_URL + "/auth/user",
method: "get",
propertyName: "user"
}
},
tokenRequired: true,
tokenName: "Authorization",
tokenType: false, //Bearer
sameSite: "None",
Secure: true
}
}
}
# auth module の使い方
自動的に auth という名前の middleware 作成されるので、該当ページに貼っておくと自動的リダイレクトしてくれます。
デフォルトの設定では、ログインページは/loginログイン後のリダイレクトページは/。トークン切れの場合自動的に/loginへリダイレクトされる仕組み。
ログインしたら返却されたデータは vuex store とクッキーに保存されます。
ログイン後使える vuex store $auth 情報
// Access using $auth
this.$auth.user;
// Access using vuex
this.$store.state.auth.user;
// Access using $auth
this.$auth.loggedIn;
// Access using vuex
this.$store.state.auth.loggedIn;
user はオブジェクト
loggedIn は boolean 型
複数のメソッド
loginWith(strategyName, ...args)
this.$auth
.loginWith("local" /* .... */)
.then(() => this.$toast.success("Logged In!"));
login(...args)
this.$auth.login(/* .... */).then(() => this.$toast.success("Logged In!"));
logout(...args)
await this.$auth.logout(/* .... */);
fetchUser()
await this.$auth.fetchUser();
hasScope(scopeName)
// Returns is a computed boolean
this.$auth.hasScope("admin");