Skip to content

Instantly share code, notes, and snippets.

@acro5piano
Last active October 22, 2017 00:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save acro5piano/818a7b8f0ec355fe996da8cbcd940939 to your computer and use it in GitHub Desktop.
Save acro5piano/818a7b8f0ec355fe996da8cbcd940939 to your computer and use it in GitHub Desktop.
Laravel 5.4 と Vue.js 2.2 と JWTAuth で、ログインできる SPA アプリケーションのチュートリアル その4 ref: http://qiita.com/acro5piano/items/eb29f13b82f386220460
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddUserIdToTasks extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('tasks', function (Blueprint $table) {
$table->integer('user_id')->references('id')->on('users')->unsigned()->index()->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('tasks', function (Blueprint $table) {
$table->dropColumn('user_id');
});
}
}
Route::group(['middleware' => 'api'], function () {
// ...
Route::get('logout', 'AuthenticateController@logout')->middleware('jwt.refresh');
// ...
});
// ...
import userStore from './stores/userStore'
// ...
const app = new Vue({
router,
el: '#app',
created () {
http.init()
userStore.init()
},
render: h => h(require('./app.vue')),
})
// ...
'providers' => [
// ...
Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
],
// ...
'aliases' => [
// ...
'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
],
];
public function logout()
{
}
public function run()
{
factory(App\User::class, 50)->create()->each(function ($user) {
$user->tasks()->save(
factory(App\Task::class)->make()
);
});
}
composer require tymon/jwt-auth
php artisan db:seed
php artisan db:seed
# 適当なユーザーを選択する
php artisan tinker
>>> App\User::first()
=> App\User {#701
id: "1",
name: "Margarette Kshlerin",
email: "laura.cartwright@example.com",
created_at: "2017-03-17 13:28:22",
updated_at: "2017-03-17 13:28:22",
}
# 適当なユーザーを選択する
php artisan tinker
>>> App\User::first()
=> App\User {#701
id: "1",
name: "Margarette Kshlerin",
email: "laura.cartwright@example.com",
created_at: "2017-03-17 13:28:22",
updated_at: "2017-03-17 13:28:22",
}
curl -XPOST localhost:8000/api/authenticate -d 'email=laura.cartwright@example.com' -d 'password=secret'
{
"user": {
"id": 1,
"name": "Margarette Kshlerin",
"email": "laura.cartwright@example.com",
"created_at": "2017-03-17 13:28:22",
"updated_at": "2017-03-17 13:28:22"
},
"token": "eyJ0eXAiOiJ******W2gvafWitgza_2H5A-g_1xS5SBkZPHde8tE"
}
curl -XGET localhost:8000/api/tasks -H 'Authorization: Bearer eyJ0eXAiOiJ******W2gvafWitgza_2H5A-g_1xS5SBkZPHde8tE'
{
"1": {
"id": 1,
"name": "Thora Strosin",
"is_done": false,
"created_at": "2017-03-16 22:39:49",
"updated_at": "2017-03-16 22:39:49",
"user_id": "1"
},
"2": {
# ...
},
"5": {
"id": 5,
"name": "August Denesik",
"is_done": true,
"created_at": "2017-03-16 22:39:49",
"updated_at": "2017-03-16 22:39:49"
"user_id": "5",
}
}
curl -XGET localhost:8000/api/tasks
{"error":"token_not_provided"}
curl -XGET localhost:8000/api/tasks -H 'Authorization: Bearer hoge.fuga.piyo'
{"error":"token_invalid"}
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
php artisan jwt:generate
php artisan make:controller AuthenticateController
# => Controller created successfully.
php artisan make:migration add_user_id_to_tasks
# => Created Migration: 2017_03_18_084344_add_user_id_to_tasks
php artisan migrate
# => Migrated: 2017_03_18_084607_add_user_id_to_tasks
// ...
delete (url, data = {}, successCb = null, errorCb = null) {
return this.request('delete', url, data, successCb, errorCb)
},
/**
* Init the service.
*/
init () {
axios.defaults.baseURL = '/api'
// Intercept the request to make sure the token is injected into the header.
axios.interceptors.request.use(config => {
config.headers['X-CSRF-TOKEN'] = window.Laravel.csrfToken
config.headers['X-Requested-With'] = 'XMLHttpRequest'
config.headers['Authorization'] = `Bearer ${localStorage.getItem('jwt-token')}` // これを追加
return config
})
// ↓ここから追加
// Intercept the response and ...
axios.interceptors.response.use(response => {
// ...get the token from the header or response data if exists, and save it.
const token = response.headers['Authorization'] || response.data['token']
if (token) {
localStorage.setItem('jwt-token', token)
}
return response
}, error => {
// Also, if we receive a Bad Request / Unauthorized error
console.log(error)
return Promise.reject(error)
})
}
// ...
protected $routeMiddleware = [
// ...
'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
];
}
<template>
<div>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Login</div>
<div class="panel-body">
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
<div class="alert alert-danger" role="alert" v-if="showAlert">
{{ alertMessage }}
</div>
<div class="form-group">
<div class="col-md-6">
<input id="email" type="email" class="form-control"
v-model="email" @keyup.enter="login" required autofocus>
</div>
</div>
<label for="password" class="col-md-4 control-label">Password</label>
<div class="form-group">
<div class="col-md-6">
<input id="password" type="password" class="form-control"
v-model="password" @keyup.enter="login" required autofocus>
</div>
</div>
<div class="form-group">
<div class="col-md-8 col-md-offset-4">
<button @click="login" type="submit" class="btn btn-primary">
Login
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import userStore from '../stores/userStore'
import http from '../services/http'
export default {
mounted () {
this.fetchUsers()
},
data() {
return {
email: '',
password: '',
showAlert: false,
alertMessage: '',
}
},
methods: {
login () {
userStore.login(this.email, this.password, res => {
this.$router.push('/')
}, error => {
this.showAlert = true
this.alertMessage = 'Wrong email or password.'
})
},
}
}
</script>
// ...
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => bcrypt('secret'),
'remember_token' => str_random(10),
];
});
// ...
<!-- ... -->
<ul class="dropdown-menu">
<li><a @click="logout()">Log out</a></li>
</ul>
<!-- ... -->
<script>
import userStore from '../stores/userStore'
export default {
data (){
return {
userState: userStore.state
}
},
methods: {
logout() {
userStore.logout( () => {
this.$router.push('/login')
})
}
}
}
</script>
public function index()
{
$user = \JWTAuth::parseToken()->authenticate();
return $user->tasks()->get()->keyBy('id');
}
public function store(Request $request)
{
$user = \JWTAuth::parseToken()->authenticate();
return $user->tasks()->create($request->only('name'))->fresh();
}
<template>
<div>
<div v-if="userState.authenticated">
<strong>Hello, {{ userState.user.name }}!</strong>
<!-- ... -->
<p v-else>
please <router-link to="/login">Login.</router-link>
</p>
</div>
</template>
<script>
import http from '../services/http'
import userStore from '../stores/userStore' // 追加
export default {
mounted() {
this.fetchTasks()
},
data() {
return {
tasks: [],
name: '',
showAlert: false,
alertMessage: '',
userState: userStore.state, // 追加
}
},
}
</script>
// To log out, we just need to remove the token
logout (successCb = null, errorCb = null) {
http.get('logout', () => {
localStorage.removeItem('jwt-token')
this.state.authenticated = false
successCb()
}, errorCb)
},
// 追加
public function tasks()
{
return $this->hasMany(Task::class);
}
// To log out, we just need to remove the token
logout (successCb = null, errorCb = null) {
http.get('logout', () => {
localStorage.removeItem('jwt-token')
this.state.authenticated = false
successCb()
}, errorCb)
},
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment