0%

Laravel API+JWT

Implementation dingo/api & tymon/jwt-auth package

Dingo/API

https://github.com/dingo/api

Install

$ laravel new api_jwt
$ cd api_jwt
$ composer require dingo/api:1.0.x@dev

Config

config/app.php

1
2
3
4
5
6
7
8
'providers' => [
Dingo\Api\Provider\LaravelServiceProvider::class
]
'aliases' => [
Dapi => Dingo\Api\Facade\API::class,
Droute => Dingo\Api\Facade\Route::class,
]

產生config/api.php
$ php artisan vendor:publish --provider="Dingo\Api\Provider\LaravelServiceProvider"

.ENV or config/api.php

.env

1
2
3
4
5
6
7
API_STANDARDS_TREE=vnd
API_SUBTYPE=myapp
API_VERSION=v1
API_PREFIX=api
API_DOMAIN=trackye.dev
API_NAME=MyAPI
API_DEBUG=true

Routes

routes/api.php

1
2
3
4
5
6
7
$api = app('Dingo\Api\Routing\Router');
$api->version('v1', function($api) {
$api->get('hello', function() {
return "Hello";
});
$api->get('world', 'App\Http\Controllers\ExampleController@index'); // return users
});

Testing

.env資料庫設定
php artisan migrate

php artisan make:seeder UsersTableSeeder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
use Illuminate\Database\Seeder;
use App\User;
use Illuminate\Support\Facades\Hash;
class UsersTableSeeder extends Seeder
{
public function run()
{
$user1 = new User();
$user1->name = 'A';
$user1->email = 'A@A.A';
$user1->password = Hash::make('A');
$user1->save();
$user2 = new User();
$user2->name = 'B';
$user2->email = 'B@B.B';
$user2->password = Hash::make('B');
$user2->save();
}
}

php artisan db:seed

php artisan api:routes

http://api_jwt.dev/api/hello
http://api_jwt.dev/api/world


前言:

  • API的用戶認證(Authorization)可以使用JWT(內部登入) or OAuth2.0(內部登入or第三方例如facebook)
  • Oauth2.0: Laravel5.3有新的Passport package, 所以不再用lucadegasperi/oauth2-server-laravel(5.2以前的解決方案)

JWT(Json Web Token)

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

Install

composer require tymon/jwt-auth:0.5.*

Config

config/app.php

1
2
3
4
5
6
7
8
'providers' => [
Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
]
'aliases' => [
'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,
]

config/api.php

1
2
3
'auth' => [
'jwt' => Dingo\Api\Auth\Provider\JWT::class,
],

產生config/jwt.php
$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"

.ENV or config/jwt.php

php artisan jwt:generate會自動加到config/jwt.php
or copy to .env

1
JWT_SECRET=npoW1xxv8yXwwQVWO3GljPO9qBncmuIb

Return Token

app/Http/Kernel.php

1
2
3
4
protected $routeMiddleware = [
'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,
'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,
];

假如使用者登入成功, return token
routes/api.php

1
$api->post('authenticate', 'App\Http\Controller\ExampleController@authenticate');

App\Http\Controllers\ExampleController.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
class ExampleController extends Controller
{
public function authenticate(Request $request)
{
// grab credentials from the request
$credentials = $request->only('email', 'password');
try {
// attempt to verify the credentials and create a token for the user
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong whilst attempting to encode the token
return response()->json(['error' => 'could_not_create_token'], 500);
}
// all good so return the token
return response()->json(compact('token'));
}
}

Example Testing

POST
api_jwt.dev/api/authenticate
email: A@A.A
Password: A

curl -X POST -H "Content-Type:application/x-www-form-urlencoded" http://api_jwt.dev/api/authenticate -d "email=A@A.A&password=A"
取得token!

Add Middleware 以下都需要token

show users

routes/api.php

1
2
3
$api->version('v1', ['middleware' => 'api.auth'], function($api){
$api->get('users', 'App\Http\Controllers\ExampleController@index');
});

PS: api.auth就是jwt(config/api.php) => jwt.auth, jwt.refresh

1
2
3
4
5
public function index()
{
$users = User::all();
return response()->json($users);
}

加入Header
Authorization: Bearer <token>
curl -H "Authorization: Bearer <token>" http://api_jwt.dev/api/users
要有token才能使用!

show user

routes/api.php

1
2
3
$api->version('v1', ['middleware' => 'api.auth'], function($api){
$api->get('user', 'App\Http\Controllers\ExampleController@show');
});

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Tymon\JWTAuth\Exceptions;
public function show()
{
try {
$user = JWTAuth::parseToken()->toUser();
if (! $user) {
return response()->json(['error' => 'User not found'], 400);
}
} catch (TokenInvalidException $e) {
return response()->json(['error' => 'Token is invalid'], 401);
} catch (TokenExpiredException $e) {
return response()->json(['error' => 'Token has expired'], 401);
} catch (TokenBlacklistedException $e) {
return response()->json(['error' => 'Token is blacklisted'], 401);
}
return response()->json($user);
}

curl -H "Authorization: Bearer <token>" http://api_jwt.dev/api/user
會根據token判斷是哪一個user, 非常厲害

refresh token

routes/api.php

1
2
3
$api->version('v1', ['middleware' => 'api.auth'], function($api){
$api->get('token', 'App\Http\Controllers\ExampleController@getToken');
});

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public function getToken()
{
$token = JWTAuth::getToken();
if (! $token) {
return response()->json(['error' => 'Token is invalid'], 401);
}
try {
$refreshedToken = JWTAuth::refresh($token);
} catch (JWTException $e) {
return response()->json(['error' => 'Something went wrong'], 400);
}
return response()->json($refreshedToken);
}

curl -H "Authorization: Bearer <token>" http://api_jwt.dev/api/token
得到傳進來的token, 返回一個新的token

delete user

routes/api.php

1
2
3
$api->version('v1', ['middleware' => 'api.auth'], function($api){
$api->delete('delete', 'App\Http\Controllers\ExampleController@destroy');
});

1
2
3
4
5
6
7
8
public function destroy()
{
$user = JWTAuth::parseToken()->authenticate();
if (! $user) {
return response()->json(['error' => 'Fail the delete provess'], 401);
}
$user->delete();
}

curl -X DELETE -H "Authorization: Bearer <token>" http://api_jwt.dev/api/delete
檢查token, 再刪user