How to implement JWT Auth About Restful API in Laravel 5.5

来源:互联网 发布:开淘宝店一个月能赚多少钱 编辑:程序博客网 时间:2024/06/05 19:08
How to implement JWT Auth About Restful API in Laravel 5.5

[myth@contoso ~]$ cd /home/myth/www && laravel new meeting

[root@contoso ~]# cat > /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.10.20    contoso.edu

[root@contoso ~]# cat > /etc/httpd/conf.d/httpd-vhosts.conf
<Directory "/home/myth/www/meeting">
        Options +Indexes +FollowSymLinks
        Order allow,deny
        Allow from all
        AllowOverride All
        Require all granted
</Directory>

<VirtualHost *:80>
    ServerAdmin zhengzizhi@126.com
    DocumentRoot "/home/myth/www/meeting/public"
    ServerName contoso.edu
    ServerAlias contoso.edu
    ErrorLog "/home/myth/log/httpd/contoso-edu-error_log"
    CustomLog "/home/myth/log/httpd/contoso-edu-access_log" common
</VirtualHost>



/home/myth/www/meeting/routes/api.php

//Route::middleware('auth:api')->get('/user', function (Request $request) {
//    return $request->user();
//});

Route::group(['prefix' => 'v1'], function() {
    Route::resource('meeting', 'MeetingController', [
        'except' => ['create', 'edit']
    ]);
    Route::resource('meeting/registration', 'RegisterController', [
        'only' => ['store', 'destroy']
    ]);
    Route::post('/user/register', [
        'uses' => 'AuthController@store'
    ]);
    Route::post('/user/signin', [
        'uses' => 'AuthController@signin'
    ]);
});


[myth@contoso ~]$ cd /home/myth/www/meeting && php artisan make:controller MeetingController --resource
[myth@contoso ~]$ cd /home/myth/www/meeting && php artisan make:controller RegisterController --resource
[myth@contoso ~]$ cd /home/myth/www/meeting && php artisan make:controller AuthController --resource



[myth@contoso meeting]$ php artisan route:list
+--------+-----------+--------------------------------------------+----------------------+-------------------------------------------------+------------+
| Domain | Method    | URI                                        | Name                 | Action                                          | Middleware |
+--------+-----------+--------------------------------------------+----------------------+-------------------------------------------------+------------+
|        | GET|HEAD  | /                                          |                      | Closure                                         | web        |
|        | GET|HEAD  | api/v1/meeting                             | meeting.index        | App\Http\Controllers\MeetingController@index    | api        |
|        | POST      | api/v1/meeting                             | meeting.store        | App\Http\Controllers\MeetingController@store    | api        |
|        | POST      | api/v1/meeting/registration                | registration.store   | App\Http\Controllers\RegisterController@store   | api        |
|        | DELETE    | api/v1/meeting/registration/{registration} | registration.destroy | App\Http\Controllers\RegisterController@destroy | api        |
|        | GET|HEAD  | api/v1/meeting/{meeting}                   | meeting.show         | App\Http\Controllers\MeetingController@show     | api        |
|        | PUT|PATCH | api/v1/meeting/{meeting}                   | meeting.update       | App\Http\Controllers\MeetingController@update   | api        |
|        | DELETE    | api/v1/meeting/{meeting}                   | meeting.destroy      | App\Http\Controllers\MeetingController@destroy  | api        |
|        | POST      | api/v1/user/register                       |                      | App\Http\Controllers\AuthController@store       | api        |
|        | POST      | api/v1/user/signin                         |                      | App\Http\Controllers\AuthController@signin      | api        |
+--------+-----------+--------------------------------------------+----------------------+-------------------------------------------------+------------+
[myth@contoso meeting]$


/home/myth/www/meeting/app/Http/Controllers/MeetingController.php
    public function store(Request $request) {
        $title = $request->input('title');
        $description = $request->input('description');
        $time = $request->input('time');
        $user_id = $request->input('user_id');
        $meeting = [
            'title' => $title,
            'description' => $description,
            'time' => $time,
            'user_id' => $user_id,
            'view_meeting' => [
                'href' => 'api/v1/meeting/1',
                'method' => 'GET'
            ],
        ];
        $response = [
            'msg' => 'Meeting created',
            'data' => $meeting,
        ];
        return response()->json($response, 201);
    }

测试工具:Postman
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/meeting

Body
Key          Value
title        年终总结大会
description  年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。
time         2017-12-30 9:30:00
user_id      1


https://laravel.com/docs/5.5/validation#available-validation-rules

/home/myth/www/meeting/.env
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:60rT/eLdGKXnDXg1UYtPVVOB0KgpDTJMuMMgaAAqkpA=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=meetingdb
DB_USERNAME=root
DB_PASSWORD=123456

BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=



[myth@contoso ~]$ cd /home/myth/www/meeting && php artisan make:model Meeting -m
[myth@contoso ~]$ cd /home/myth/www/meeting && php artisan make:migration create_meeting_user_table --create=meeting_user

/home/myth/www/meeting/database/migrations/2017_12_18_090430_create_meetings_table.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateMeetingsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('meetings', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('meetings');
    }
}

/home/myth/www/meeting/database/migrations/2017_12_18_090445_create_meeting_user_table.php

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateMeetingUserTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('meeting_user', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('meeting_user');
    }
}



定义表结构字段类型:
/home/myth/www/meeting/database/migrations/2017_12_18_090445_create_meeting_user_table.php
    public function up()
    {
        Schema::create('meeting_user', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned();
            $table->integer('meeting_id')->unsigned();
            $table->timestamps();
        });
    }

/home/myth/www/meeting/database/migrations/2017_12_18_090430_create_meetings_table.php
    public function up()
    {
        Schema::create('meetings', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->text('description');
            $table->timestamp('time');
            $table->timestamps();
        });
    }


[myth@contoso meeting]$ cd /home/myth/www/meeting && php artisan migrate
Migrating: 2017_12_18_090430_create_meetings_table
Migrated:  2017_12_18_090430_create_meetings_table
Migrating: 2017_12_18_090445_create_meeting_user_table
Migrated:  2017_12_18_090445_create_meeting_user_table

/home/myth/www/meeting/app/User.php
    public function meetings() {
        return $this->belongsToMany(Meeting::class);
    }

/home/myth/www/meeting/app/Meeting.php
<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class Meeting extends Model {

    protected $fillable = ['title', 'description', 'time'];

    public function users() {
         return $this->belongsToMany(User::class);
    }

}

/home/myth/www/meeting/app/Http/Controllers/AuthController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;

class AuthController extends Controller {

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request) {
        $this->validate($request, [
            'name' => 'required',
            'email' => 'required|email',
            'password' => 'required|min:5',
        ]);
        $name = $request->input('name');
        $email = $request->input('email');
        $password = $request->input('password');
        $user = new User([
            'name' => $name,
            'email' => $email,
            'password' => bcrypt($password),
        ]);
        if ($user->save()) {
            $user->signin = [
                'href' => 'api/v1/user/signin',
                'method' => 'POST',
                'params' => 'email,password',
            ];
            $response = [
                'msg' => 'User created',
                'user' => $user,
            ];
            return response()->json($response, 201);
        }
        $response = [
            'msg' => 'An error occurred',
        ];
        return response()->json($response, 404);
    }

    /**
     *
     * @param  \Illuminate\Http\Request  $request
     */
    public function signin(Request $request) {
        //
    }

}

测试工具:Postman
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/user/register

Body
Key          Value
name         John
email        john@126.com
password     123456



# /home/myth/www/meeting/app/Http/Controllers/MeetingController.php
<?php

namespace App\Http\Controllers;
use App\Meeting;
use Illuminate\Http\Request;

class MeetingController extends Controller {

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index() {
        $meetings = Meeting::all();
        foreach ($meetings as $meeting) {
            $meeting->view_meeting = [
                'href' => 'api/v1/meeting/' . $meeting->id,
                'method' => 'GET'
            ];
        }
        $response = [
            'msg' => 'List of all Meetings',
            'meetings' => $meetings
        ];
        return response()->json($response, 200);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request) {
        $this->validate($request, [
            'title' => 'required',
            'description' => 'required',
            'time' => 'required',
            'user_id' => 'required',
        ]);

        $title = $request->input('title');
        $description = $request->input('description');
        $time = $request->input('time');
        $user_id = $request->input('user_id');

        $meeting = new Meeting([
            'title' => $title,
            'description' => $description,
            'time' => $time,
        ]);

        if ($meeting->save()) {
            $meeting->users()->attach($user_id);
            $meeting->view_meeting = [
                'href' => 'api/v1/meeting/' . $meeting->id,
                'method' => 'GET'
            ];
            $message = [
                'message' => 'Meeting created',
                'meeting' => $meeting,
            ];
            return response()->json($message, 201);
        }
        $response = [
            'message' => 'Error during creating'
        ];
        return response()->json($response, 404);
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id) {
        $meeting = Meeting::with('users')->where('id', $id)->firstOrFail();
        $meeting->view_meetings = [
            'href' => 'api/v1/meeting',
            'method' => 'GET'
        ];
        $response = [
            'message' => 'Meeting information',
            'meeting' => $meeting
        ];
        return response()->json($response, 200);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id) {
        $this->validate($request, [
            'title' => 'required',
            'description' => 'required',
            'time' => 'required',
            'user_id' => 'required'
        ]);
        $title = $request->input('title');
        $description = $request->input('description');
        $time = $request->input('time');
        $user_id = $request->input('user_id');
        $meeting = Meeting::with('users')->findOrFail($id);
        if (!$meeting->users()->where('users.id', $user_id)->first()) {
            return response()->json(['message' => 'user not registered for meeting, update not successful'], 401);
        };
        $meeting->time = $time;
        $meeting->title = $title;
        $meeting->description = $description;
        if (!$meeting->update()) {
            return response()->json([
                        'message' => 'Error during update'
                            ], 404);
        }
        $meeting->view_meeting = [
            'href' => 'api/v1/meeting/' . $meeting->id,
            'method' => 'GET'
        ];
        $response = [
            'message' => 'Meeting Updated',
            'meeting' => $meeting
        ];
        return response()->json($response, 200);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id) {
        $meeting = Meeting::findOrFail($id);
        $users = $meeting->users;
        $meeting->users()->detach();
        if(!$meeting->delete()){
            foreach ($users as $user){
                $meeting->users()->attach($user);
            }
            return response()->json([
                'message' => 'Deletion Failed'
            ], 404);
        }
        $response = [
            'message' => 'Meeting deleted',
            'create' => [
                'href' => 'api/v1/meeting',
                'method' => 'POST',
                'params' => 'title, description, time'
            ]
        ];
        return response()->json($response, 200);
    }

}

测试工具:Postman
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/meeting

Body
Key          Value
title        年终总结大会
description  年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。
time         2017-12-30 9:30:00
user_id      1

Output:

{
    "message": "Meeting created",
    "meeting": {
        "title": "年终总结大会",
        "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
        "time": "2017-12-30 9:30:00",
        "updated_at": "2017-12-18 15:27:29",
        "created_at": "2017-12-18 15:27:29",
        "id": 4,
        "view_meeting": {
            "href": "api/v1/meeting/4",
            "method": "GET"
        }
    }
}

测试工具:Postman
Headers
Key          Value
Accept       application/json

GET          http://contoso.edu/api/v1/meeting/4

Output:

{
    "message": "Meeting information",
    "meeting": {
        "id": 4,
        "title": "年终总结大会",
        "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
        "time": "2017-12-30 09:30:00",
        "created_at": "2017-12-18 15:27:29",
        "updated_at": "2017-12-18 15:27:29",
        "view_meetings": {
            "href": "api/v1/meeting",
            "method": "GET"
        },
        "users": [
            {
                "id": 1,
                "name": "John",
                "email": "john@126.com",
                "created_at": "2017-12-18 13:50:39",
                "updated_at": "2017-12-18 13:50:39",
                "pivot": {
                    "meeting_id": 4,
                    "user_id": 1
                }
            }
        ]
    }
}


测试工具:Postman
Headers
Key          Value
Accept       application/json

GET          http://contoso.edu/api/v1/meeting

Output:

{
    "msg": "List of all Meetings",
    "meetings": [
        {
            "id": 4,
            "title": "年终总结大会",
            "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
            "time": "2017-12-30 09:30:00",
            "created_at": "2017-12-18 15:27:29",
            "updated_at": "2017-12-18 15:27:29",
            "view_meeting": {
                "href": "api/v1/meeting/4",
                "method": "GET"
            }
        }
    ]
}




测试工具:Postman  模拟HTML网页界面的修改记录,把会议时间改为2017-12-30 14:30:00
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/meeting/4

Body
Key          Value
_method      PATCH
title        年终总结大会
description  年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。
time         2017-12-30 14:30:00
user_id      1

Output:

{
    "message": "Meeting Updated",
    "meeting": {
        "id": 4,
        "title": "年终总结大会",
        "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
        "time": "2017-12-30 14:30:00",
        "created_at": "2017-12-18 15:27:29",
        "updated_at": "2017-12-18 15:53:39",
        "view_meeting": {
            "href": "api/v1/meeting/4",
            "method": "GET"
        },
        "users": [
            {
                "id": 1,
                "name": "John",
                "email": "john@126.com",
                "created_at": "2017-12-18 13:50:39",
                "updated_at": "2017-12-18 13:50:39",
                "pivot": {
                    "meeting_id": 4,
                    "user_id": 1
                }
            }
        ]
    }
}



测试工具:Postman  模拟HTML网页界面的删除记录
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/meeting/4

Body
Key          Value
_method      DELETE

Output:

{
    "message": "Meeting deleted",
    "create": {
        "href": "api/v1/meeting",
        "method": "POST",
        "params": "title, description, time"
    }
}


# /home/myth/www/meeting/app/Http/Controllers/RegisterController.php
<?php
namespace App\Http\Controllers;

use App\User;
use App\Meeting;
use Illuminate\Http\Request;

class RegisterController extends Controller {

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request) {
        $this->validate($request, [
            'meeting_id' => 'required',
            'user_id' => 'required',
        ]);
        $meeting_id = $request->input('meeting_id');
        $user_id = $request->input('user_id');
        $meeting = Meeting::findOrFail($meeting_id);
        $user = User::findOrFail($user_id);
        $message = [
            'message' => 'User is already registered for meeting',
            'user' => $user,
            'meeting' => $meeting,
            'unregister' => [
                'href' => 'api/v1/meeting/registration/' . $meeting->id,
                'method' => 'DELETE',
            ]
        ];
        if ($meeting->users()->where('users.id', $user->id)->first()) {
            return response()->json($message, 404);
        };
        $user->meetings()->attach($meeting);
        $response = [
            'message' => 'User registered for meeting',
            'meeting' => $meeting,
            'user' => $user,
            'unregister' => [
                'href' => 'api/v1/meeting/registration/' . $meeting->id,
                'method' => 'DELETE'
            ]
        ];
        return response()->json($response, 201);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id) {
        $meeting = Meeting::findOrFail($id);
        $meeting->users()->detach();
        $response = [
            'message' => 'User unregistered for meeting',
            'meeting' => $meeting,
            'user' => 'tbd',
            'register' => [
                'href' => 'api/v1/meeting/registration',
                'method' => 'POST',
                'params' => 'user_id, meeting_id'
            ]
        ];
        return response()->json($response, 200);
    }

}



测试工具:Postman
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/meeting

Body
Key          Value
title        年终总结大会
description  年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。
time         2017-12-30 9:30:00
user_id      1

Output:

{
    "message": "Meeting created",
    "meeting": {
        "title": "年终总结大会",
        "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
        "time": "2017-12-30 9:30:00",
        "updated_at": "2017-12-19 05:23:46",
        "created_at": "2017-12-19 05:23:46",
        "id": 5,
        "view_meeting": {
            "href": "api/v1/meeting/5",
            "method": "GET"
        }
    }
}

测试工具:Postman  至少添加1条meeting记录,
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/meeting/registration

Body
Key          Value
user_id      1
meeting_id   5

Output:

{
    "message": "User is already registered for meeting",
    "user": {
        "id": 1,
        "name": "John",
        "email": "john@126.com",
        "created_at": "2017-12-18 13:50:39",
        "updated_at": "2017-12-18 13:50:39"
    },
    "meeting": {
        "id": 5,
        "title": "年终总结大会",
        "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
        "time": "2017-12-30 09:30:00",
        "created_at": "2017-12-19 05:23:46",
        "updated_at": "2017-12-19 05:23:46"
    },
    "unregister": {
        "href": "api/v1/meeting/registration/5",
        "method": "DELETE"
    }
}


测试工具:Postman
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/user/register

Body
Key          Value
name         Jack
email        jack@136.com
password     123456

Output:

{
    "msg": "User created",
    "user": {
        "name": "Jack",
        "email": "jack@136.com",
        "updated_at": "2017-12-19 05:34:44",
        "created_at": "2017-12-19 05:34:44",
        "id": 2,
        "signin": {
            "href": "api/v1/user/signin",
            "method": "POST",
            "params": "email,password"
        }
    }
}


测试工具:Postman  至少需要添加1条meeting记录,
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/meeting/registration

Body
Key          Value
user_id      2
meeting_id   5

Output:

{
    "message": "User registered for meeting",
    "meeting": {
        "id": 5,
        "title": "年终总结大会",
        "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
        "time": "2017-12-30 09:30:00",
        "created_at": "2017-12-19 05:23:46",
        "updated_at": "2017-12-19 05:23:46"
    },
    "user": {
        "id": 2,
        "name": "Jack",
        "email": "jack@136.com",
        "created_at": "2017-12-19 05:34:44",
        "updated_at": "2017-12-19 05:34:44"
    },
    "unregister": {
        "href": "api/v1/meeting/registration/5",
        "method": "DELETE"
    }
}


测试工具:Postman  
Headers
Key          Value
Accept       application/json

GET          http://contoso.edu/api/v1/meeting/5


Output:

{
    "message": "Meeting information",
    "meeting": {
        "id": 5,
        "title": "年终总结大会",
        "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
        "time": "2017-12-30 09:30:00",
        "created_at": "2017-12-19 05:23:46",
        "updated_at": "2017-12-19 05:23:46",
        "view_meetings": {
            "href": "api/v1/meeting",
            "method": "GET"
        },
        "users": [
            {
                "id": 1,
                "name": "John",
                "email": "john@126.com",
                "created_at": "2017-12-18 13:50:39",
                "updated_at": "2017-12-18 13:50:39",
                "pivot": {
                    "meeting_id": 5,
                    "user_id": 1
                }
            },
            {
                "id": 2,
                "name": "Jack",
                "email": "jack@136.com",
                "created_at": "2017-12-19 05:34:44",
                "updated_at": "2017-12-19 05:34:44",
                "pivot": {
                    "meeting_id": 5,
                    "user_id": 2
                }
            }
        ]
    }
}


测试工具:Postman  
Headers
Key          Value
Accept       application/json

POST          http://contoso.edu/api/v1/meeting/registration/1

Body
Key          Value
_method      DELETE

Output:

{
    "message": "User unregistered for meeting",
    "meeting": {
        "id": 5,
        "title": "年终总结大会",
        "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
        "time": "2017-12-30 09:30:00",
        "created_at": "2017-12-19 05:23:46",
        "updated_at": "2017-12-19 05:23:46"
    },
    "user": "tbd",
    "register": {
        "href": "api/v1/meeting/registration",
        "method": "POST",
        "params": "user_id, meeting_id"
    }
}

select * from `meetings` where `meetings`.`id` = '5' limit 1;
delete from `meeting_user` where `meeting_id` = 5;


测试工具:Postman  
Headers
Key          Value
Accept       application/json

POST          http://contoso.edu/api/v1/meeting/5

Output:

{
    "message": "Meeting information",
    "meeting": {
        "id": 5,
        "title": "年终总结大会",
        "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
        "time": "2017-12-30 09:30:00",
        "created_at": "2017-12-19 05:23:46",
        "updated_at": "2017-12-19 05:23:46",
        "view_meetings": {
            "href": "api/v1/meeting",
            "method": "GET"
        },
        "users": []
    }
}



https://github.com/barryvdh/laravel-cors
如何在Laravel5.5框架中使用JWT(Json Web Token) Auth

[myth@contoso ~]$ cd /home/myth/www/meeting && composer require barryvdh/laravel-cors  # 安装需要的插件
Using version ^0.10.0 for barryvdh/laravel-cors
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing barryvdh/laravel-cors (v0.10.0): Downloading (100%)         
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: barryvdh/laravel-cors
Package manifest generated successfully.
[myth@contoso meeting]$


/home/myth/www/meeting/config/app.php
'providers' => [
    ... ...
    ... ...

        /*
         * Package Service Providers...
         */
        Barryvdh\Cors\ServiceProvider::class,
    ... ...
    ... ...
    ],


[myth@contoso ~]$ cd /home/myth/www/meeting && php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider"
Copied File [/vendor/barryvdh/laravel-cors/config/cors.php] To [/config/cors.php]
Publishing complete.
[myth@contoso meeting]$


/home/myth/www/meeting/app/Http/Kernel.php
$app->routeMiddleware([
    // ...
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'cors' => \Barryvdh\Cors\HandleCors::class,
]);

https://github.com/tymondesigns/jwt-auth
https://github.com/tymondesigns/jwt-auth/wiki
https://github.com/tymondesigns/jwt-auth/wiki/Installation

/home/myth/www/meeting/config/app.php
'providers' => [
    ... ...
    ... ...

        /*
         * Package Service Providers...
         */
        Barryvdh\Cors\ServiceProvider::class,
        Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
    ... ...
    ... ...
    ],

[myth@contoso ~]$ cd /home/myth/www/meeting && composer require tymon/jwt-auth
Using version ^0.5.12 for tymon/jwt-auth
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 4 installs, 0 updates, 0 removals
  - Installing symfony/polyfill-util (v1.6.0): Downloading (100%)         
  - Installing symfony/polyfill-php56 (v1.6.0): Downloading (100%)         
  - Installing namshi/jose (7.2.3): Downloading (100%)         
  - Installing tymon/jwt-auth (0.5.12): Downloading (100%)         
namshi/jose suggests installing phpseclib/phpseclib (Allows to use Phpseclib as crypto engine, use version ^2.0.)
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: barryvdh/laravel-cors
Package manifest generated successfully.
[myth@contoso meeting]$

/home/myth/www/meeting/config/app.php
'aliases' => [
    ... ...
    ... ...

        'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
        'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
    ],


[myth@contoso ~]$ cd /home/myth/www/meeting && php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
Copied File [/vendor/tymon/jwt-auth/src/config/config.php] To [/config/jwt.php]
Publishing complete.
[myth@contoso meeting]$


[myth@contoso ~]$ cd /home/myth/www/meeting && php artisan jwt:generate
In BoundMethod.php line 135:                                                                          
  Method Tymon\JWTAuth\Commands\JWTGenerateCommand::handle() does not exist                                                                       
[myth@contoso meeting]$
解决办法是扩展一个public function handle()方法:
/home/myth/www/meeting/vendor/tymon/jwt-auth/src/Commands/JWTGenerateCommand.php
    public function handle(){
        $this->fire();
    }

[myth@contoso ~]$ cd /home/myth/www/meeting && php artisan jwt:generate
jwt-auth secret [Vrw8j8w4tyrmwYKIffIgMy0Vs4evIpWZ] set successfully.
[myth@contoso meeting]$
命令执行成功后,删掉刚刚扩展进来的public function handle()方法


[myth@contoso ~]$ cd /home/myth/www/meeting && php artisan make:middleware VerifyJWTToken
Middleware created successfully.
[myth@contoso meeting]$

# /home/myth/www/meeting/app/Http/Middleware/VerifyJWTToken.php
<?php
namespace App\Http\Middleware;

use Closure;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;

class VerifyJWTToken {

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next) {
        try {
            $user = JWTAuth::toUser($request->input('token'));
        } catch (JWTException $e) {
            if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException) {
                return response()->json(['token_expired'], $e->getStatusCode());
            } else if ($e instanceof \Tymon\JWTAuth\Exceptions\TokenInvalidException) {
                return response()->json(['token_invalid'], $e->getStatusCode());
            } else {
                return response()->json(['error' => 'Token is required']);
            }
        }
        return $next($request);
    }

}


/home/myth/www/meeting/app/Http/Kernel.php
    protected $routeMiddleware = [
        'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'cors' => \Barryvdh\Cors\HandleCors::class,
        'jwt.auth' => \App\Http\Middleware\VerifyJWTToken::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    ];



/home/myth/www/meeting/app/Http/Controllers/AuthController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use JWTAuth;
use JWTAuthException;
use App\User;

class AuthController extends Controller {

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request) {
        $this->validate($request, [
            'name' => 'required',
            'email' => 'required|email',
            'password' => 'required|min:5'
        ]);
        $name = $request->input('name');
        $email = $request->input('email');
        $password = $request->input('password');
        $user = new User([
            'name' => $name,
            'email' => $email,
            'password' => bcrypt($password)
        ]);
        // JWTAuth
        $credentials = [
            'email' => $email,
            'password' => $password
        ];
        if ($user->save()) {
            $token = null;
            try {
                if (!$token = JWTAuth::attempt($credentials)) {
                    return response()->json([
                                'message' => 'Email or Password are incorrect',
                                    ], 404);
                }
            } catch (JWTAuthException $e) {
                return response()->json([
                            'message' => 'failed_to_create_token',
                                ], 404);
            }
            $user->signin = [
                'href' => 'api/v1/user/signin',
                'method' => 'POST',
                'params' => 'email, password'
            ];
            $response = [
                'message' => 'User created',
                'user' => $user,
                'token' => $token
            ];
            return response()->json($response, 201);
        }
        $response = [
            'message' => 'An error occurred'
        ];
        return response()->json($response, 404);
    }

    /**
     *
     * @param  \Illuminate\Http\Request  $request
     */
    public function signin(Request $request) {
        //
    }

}


测试工具:Postman
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/user/register

Body
Key          Value
name         Jim
email        jim@136.com
password     123456

Output:

{
    "message": "User created",
    "user": {
        "name": "Jim",
        "email": "jim@136.com",
        "updated_at": "2017-12-19 08:19:42",
        "created_at": "2017-12-19 08:19:42",
        "id": 3,
        "signin": {
            "href": "api/v1/user/signin",
            "method": "POST",
            "params": "email, password"
        }
    },
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjMsImlzcyI6Imh0dHA6Ly9jb250b3NvLmVkdS9hcGkvdjEvdXNlci9yZWdpc3RlciIsImlhdCI6MTUxMzY3MTU4MiwiZXhwIjoxNTEzNjc1MTgyLCJuYmYiOjE1MTM2NzE1ODIsImp0aSI6IlFabTVjV1FHcHExQjlFRE4ifQ.d_EviHE2hNnq47CGEwp5wkj_A5DWIlR5bEZs4oi_11Q"
}





/home/myth/www/meeting/app/Http/Controllers/AuthController.php
    public function signin(Request $request) {
        $this->validate($request, [
            'email' => 'required|email',
            'password' => 'required|min:5'
        ]);
        $email = $request->input('email');
        $password = $request->input('password');
        if ($user = User::where('email', $email)->first()) {
            $credentials = [
                'email' => $email,
                'password' => $password
            ];
            $token = null;
            try {
                if (!$token = JWTAuth::attempt($credentials)) {
                    return response()->json([
                                'message' => 'Email or Password are incorrect',
                                    ], 404);
                }
            } catch (JWTAuthException $e) {
                return response()->json([
                            'message' => 'failed_to_create_token',
                                ], 404);
            }
            $response = [
                'message' => 'User signin',
                'user' => $user,
                'token' => $token
            ];
            return response()->json($response, 201);
        }
        $response = [
            'message' => 'An error occurred'
        ];
        return response()->json($response, 404);
    }
 
测试工具:Postman
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/user/signin

Body
Key          Value
email        jim@136.com
password     123456

Output:

{
    "message": "User signin",
    "user": {
        "id": 3,
        "name": "Jim",
        "email": "jim@136.com",
        "created_at": "2017-12-19 08:19:42",
        "updated_at": "2017-12-19 08:19:42"
    },
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjMsImlzcyI6Imh0dHA6Ly9jb250b3NvLmVkdS9hcGkvdjEvdXNlci9zaWduaW4iLCJpYXQiOjE1MTM2NzQzMTIsImV4cCI6MTUxMzY3NzkxMiwibmJmIjoxNTEzNjc0MzEyLCJqdGkiOiJncWg0OFI3OE54NGpQVGNzIn0.cr3qSgEGXPvvZEzlH2MJnaUILXpcMq9APoWn6rKpB_o"
}






# /home/myth/www/meeting/app/Http/Controllers/MeetingController.php
    public function __construct() {
        $this->middleware('jwt.auth');
    }

# /home/myth/www/meeting/routes/api.php  插入'middleware' => 'cors'
<?php
use Illuminate\Http\Request;

Route::group(['prefix' => 'v1', 'middleware' => 'cors'], function() {
    Route::resource('meeting', 'MeetingController', [
        'except' => ['create', 'edit']
    ]);
    Route::resource('meeting/registration', 'RegisterController', [
        'only' => ['store', 'destroy']
    ]);
    Route::post('/user/register', [
        'uses' => 'AuthController@store'
    ]);
    Route::post('/user/signin', [
        'uses' => 'AuthController@signin'
    ]);
});


# /home/myth/www/meeting/app/Http/Controllers/RegisterController.php
use JWTAuth;

    public function __construct() {
        $this->middleware('jwt.auth');
    }






测试工具:Postman
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/user/signin

Body
Key          Value
email        jim@136.com
password     123456

Output:

{
    "message": "User signin",
    "user": {
        "id": 3,
        "name": "Jim",
        "email": "jim@136.com",
        "created_at": "2017-12-19 08:19:42",
        "updated_at": "2017-12-19 08:19:42"
    },
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjMsImlzcyI6Imh0dHA6Ly9jb250b3NvLmVkdS9hcGkvdjEvdXNlci9zaWduaW4iLCJpYXQiOjE1MTM2NzY2NzQsImV4cCI6MTUxMzY4MDI3NCwibmJmIjoxNTEzNjc2Njc0LCJqdGkiOiJzd3ZRdlMxbmJmdEZvWVpVIn0.vxMRIK091bvv8HjimmsThahWg4zwgizdzJGfBNViaag"

}



测试工具:Postman
Headers
Key          Value
Accept       application/json

GET          http://contoso.edu/api/v1/meeting

Body
Key          Value


Output:

{
    "error": "Token is required"
}


使用登录api接口获得的Token再一次提交请求:
Headers
Key          Value
Accept       application/json

GET          http://contoso.edu/api/v1/meeting

点击Params
Key          Value
token        eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjMsImlzcyI6Imh0dHA6Ly9jb250b3NvLmVkdS9hcGkvdjEvdXNlci9zaWduaW4iLCJpYXQiOjE1MTM2NzY2NzQsImV4cCI6MTUxMzY4MDI3NCwibmJmIjoxNTEzNjc2Njc0LCJqdGkiOiJzd3ZRdlMxbmJmdEZvWVpVIn0.vxMRIK091bvv8HjimmsThahWg4zwgizdzJGfBNViaag

Output:

{
    "msg": "List of all Meetings",
    "meetings": [
        {
            "id": 5,
            "title": "年终总结大会",
            "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
            "time": "2017-12-30 09:30:00",
            "created_at": "2017-12-19 05:23:46",
            "updated_at": "2017-12-19 05:23:46",
            "view_meeting": {
                "href": "api/v1/meeting/5",
                "method": "GET"
            }
        }
    ]
}

等价于链接(Token值来自登录成功后返回的Token):
http://contoso.edu/api/v1/meeting?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjMsImlzcyI6Imh0dHA6Ly9jb250b3NvLmVkdS9hcGkvdjEvdXNlci9zaWduaW4iLCJpYXQiOjE1MTM2NzY2NzQsImV4cCI6MTUxMzY4MDI3NCwibmJmIjoxNTEzNjc2Njc0LCJqdGkiOiJzd3ZRdlMxbmJmdEZvWVpVIn0.vxMRIK091bvv8HjimmsThahWg4zwgizdzJGfBNViaag



# /home/myth/www/meeting/app/Http/Controllers/MeetingController.php
    public function __construct() {
        //$this->middleware('jwt.auth');
        $this->middleware(
                'jwt.auth', ['except' => ['index', 'show']]
        );
    }

测试工具:Postman
Headers
Key          Value
Accept       application/json

GET          http://contoso.edu/api/v1/meeting

Output:

{
    "message": "Meeting information",
    "meeting": {
        "id": 5,
        "title": "年终总结大会",
        "description": "年终总结是人们对一年来的工作学习进行 回顾和分析,从中找出经验和教训,引出规律性认识,以 指导今后工作和实践活动的一种应用文体。年终总结的内容包括一年来的情况概述、成绩和经验教训、今后努力的方向。",
        "time": "2017-12-30 09:30:00",
        "created_at": "2017-12-19 05:23:46",
        "updated_at": "2017-12-19 05:23:46",
        "view_meetings": {
            "href": "api/v1/meeting",
            "method": "GET"
        },
        "users": []
    }
}



测试工具:Postman  
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/meeting

Body
Key          Value
title        每周例会
description  汇报上周工作内容和末完成的工作,收集同事们合理化的建议和解决问题的办法,安排本周工作计划。
time         2017-12-18 9:30:00
user_id      2

Output:

{
    "error": "Token is required"
}


测试工具:Postman
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/user/signin

Body
Key          Value
email        jack@136.com
password     123456

Output:

{
    "message": "User signin",
    "user": {
        "id": 2,
        "name": "Jack",
        "email": "jack@136.com",
        "created_at": "2017-12-19 05:34:44",
        "updated_at": "2017-12-19 05:34:44"
    },
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIsImlzcyI6Imh0dHA6Ly9jb250b3NvLmVkdS9hcGkvdjEvdXNlci9zaWduaW4iLCJpYXQiOjE1MTM2ODkwNjQsImV4cCI6MTUxMzY5MjY2NCwibmJmIjoxNTEzNjg5MDY0LCJqdGkiOiJUNVdJZGJ0dW9oVlV4a05GIn0.mpylls1GOU0iLIyftcLrBjlkU8jatzZTsHql0NXED84"
}


测试工具:Postman  使用登录返回的Token来创建新记录
Headers
Key          Value
Accept       application/json

POST         http://contoso.edu/api/v1/meeting

Body
Key          Value
title        每周例会
description  汇报上周工作内容和末完成的工作,收集同事们合理化的建议和解决问题的办法,安排本周工作计划。
time         2017-12-18 9:30:00
user_id      2
token        eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIsImlzcyI6Imh0dHA6Ly9jb250b3NvLmVkdS9hcGkvdjEvdXNlci9zaWduaW4iLCJpYXQiOjE1MTM2ODkwNjQsImV4cCI6MTUxMzY5MjY2NCwibmJmIjoxNTEzNjg5MDY0LCJqdGkiOiJUNVdJZGJ0dW9oVlV4a05GIn0.mpylls1GOU0iLIyftcLrBjlkU8jatzZTsHql0NXED84

Output:

{
    "message": "Meeting created",
    "meeting": {
        "title": "每周例会",
        "description": "汇报上周工作内容和末完成的工作,收集同事们合理化的建议和解决问题的办法,安排本周工作计划。",
        "time": "2017-12-18 9:30:00",
        "updated_at": "2017-12-19 13:12:58",
        "created_at": "2017-12-19 13:12:58",
        "id": 6,
        "view_meeting": {
            "href": "api/v1/meeting/6",
            "method": "GET"
        }
    }
}


# /home/myth/www/meeting/app/Http/Controllers/RegisterController.php

    public function destroy($id) {
        $user = JWTAuth::toUser($request['token']);
        $meeting = Meeting::findOrFail($id);
        $meeting->users()->detach($user->id);
        
        $response = [
            'message' => 'User unregistered for meeting',
            'meeting' => $meeting,
            'user' => 'tbd',
            'register' => [
                'href' => 'api/v1/meeting/registration',
                'method' => 'POST',
                'params' => 'user_id, meeting_id'
            ]
        ];
        return response()->json($response, 200);
    }