参考:https://medium.com/tech-tajawal/jwt-authentication-for-lumen-5-6-2376fd38d454
1.Add JWT_SECRET=xxxx to yours.env file
APP_KEY=1111
JWT_SECRET=111
2. Create a migration file for the users table:
php artisan make:migration create_users_table
3. Modify the migration file created inside the database/migrations
directory
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
4. create the seeder to populate the database with some users. Modify database/seeds/UsersTableSeeder.php
to look like:
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('users')->insertOrIgnore(
[
[
'name' => 'Admin',
'email' => 'administrator@app.com',
'password' => Hash::make('password'),
],
[
'name' => 'Editor',
'email' => 'editor@app.com',
'password' => Hash::make('password'),
],
[
'name' => 'User',
'email' => 'user@app.com',
'password' => Hash::make('password'),
]
]
);
}
5. Now create the configured database in MySQL and run the following commands inside your terminal to create the users table and add some dummy data respectively:
php artisan migrate
php artisan db:seed
Now your database looks something like this:
6. Lumen does not have facades and eloquent enabled by default, let’s enable them first by opening the bootstrap/app.php
file and uncomment the following lines:
$app->withFacades();
$app->withEloquent();
7. Now let’s create the endpoint to generate JWT token. There are tons of libraries out there that will help you with it we will use the one called firebase/php-jwt
. Open up your terminal and run the following command to pull it in using composer:
composer require firebase/php-jwt
8. Now let’s add the endpoint POST /auth/v1/login
that will accept the credentials and return a token for us. Let’s register the route first by adding the following route inside routes/web.php
file:
$router->group(['prefix' => 'auth/v1'], function () use ($router) {
$router->post('login', 'AuthController@login');
});
8. Now we need the controller AuthController
with method authenticate
. Inside app/Http/Controllers
folder create a new AuthController.php
file and put following content inside it:
<?php
namespace App\Http\Controllers;
use Validator;
use App\User;
use Firebase\JWT\JWT;
use Illuminate\Http\Request;
use Firebase\JWT\ExpiredException;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
private $request;
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Get a JWT via given credentials.
*
* @return \Illuminate\Http\JsonResponse
*/
public function login(User $user)
{
$this->validate($this->request, [
'email' => 'required|email',
'password' => 'required'
]);
// Find the user by email
$user = User::where('email', $this->request->input('email'))->first();
if (!$user) {
// You wil probably have some sort of helpers or whatever
// to make sure that you have the same response format for
// differents kind of responses. But let's return the
// below respose for now.
return response()->json([
'error' => 'Email does not exist.'
], 400);
}
// Verify the password and generate the token
if (Hash::check($this->request->input('password'), $user->password)) {
return response()->json([
'token' => $this->jwt($user),
'token_type' => 'bearer',
'data' => $user
], 200);
}
// Bad Request response
return response()->json([
'error' => 'Email or password is wrong.'
], 400);
}
/**
* Get the authenticated User.
*
* @return \Illuminate\Http\JsonResponse
*/
public function me()
{
$user = Auth::user();
return response()->json($user);
}
/**
* Create a new token.
*
* @param \App\User $user
* @return string
*/
protected function jwt(User $user)
{
$payload = [
'iss' => "lumen-jwt", // Issuer of the token
'sub' => $user->id, // Subject of the token
'iat' => time(), // Time when JWT was issued.
'exp' => time() + 60 * 60 // Expiration time
];
// As you can see we are passing `JWT_SECRET` as the second parameter that will
// be used to decode the token in the future.
return JWT::encode($payload, env('JWT_SECRET'));
}
}
10. Let’s open up your terminal and then run the application by running the following command:
php -S localhost:8000 -t public
11. Now to test our application i am using Postman. Inside postman create a new request to http://localhost:8000/auth/v1/login
. When you hist this route by clicking the send button you will get the the token in response body.
12. Authentication
Uncomment lines in bootstrap/app.php
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
]);
......
$app->register(App\Providers\AuthServiceProvider::class);
13. Now let’s protect some of our routes. Open the routes file i.e. routes/web.php
and put the following routes inside it:
$router->group(['middleware' => 'auth'], function () use ($router) {
$router->group(['prefix' => 'auth/v1'], function () use ($router) {
$router->post('me', 'AuthController@me');
});
});
14. After updating the routes file test if our request succeeds by hitting http://localhost:8000/auth/v1/me route. This request will fail because this is a protected route and require us to provide a token.
15. let’s edit App\HTTP\Middleware\Authenticate.php
<?php
namespace App\Http\Middleware;
use App\User;
use Closure;
use Exception;
use Firebase\JWT\JWT;
use Firebase\JWT\ExpiredException;
use Illuminate\Contracts\Auth\Factory as Auth;
class Authenticate
{
/**
* The authentication guard factory instance.
*
* @var \Illuminate\Contracts\Auth\Factory
*/
protected $auth;
/**
* Create a new middleware instance.
*
* @param \Illuminate\Contracts\Auth\Factory $auth
* @return void
*/
public function __construct(Auth $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
// check dose token provided
$token = $request->header('authorization');
if (is_null($token)) {
// Unauthorized response if token not there
return response([
'code' => 'no_token',
'message' => 'Token not provided.',
'data' => [
'status' => 401
]
], 401);
}
// decode and check Token
$token = str_replace('Bearer ', '', $token);
try {
$token = str_replace('Bearer ', '', $token);
$credentials = JWT::decode($token, env('JWT_SECRET'), ['HS256']);
$user = User::find($credentials->sub);
if (!$user) {
return response([
'code' => 'user_not_found',
'message' => 'User not found',
'data' => [
'status' => 400,
]
], 400);
}
// Now let's put the user in the request class so that you can grab it from there
$request->auth = $user;
} catch (ExpiredException $e) {
return response([
'code' => 'token_expired',
'message' => 'Provided token is expired.',
'data' => [
'status' => 400,
]
], 400);
} catch (Exception $e) {
return response([
'code' => 'decode_token_failed',
'message' => 'An error while decoding token.',
'data' => [
'status' => 400,
]
], 400);
}
return $next($request);
}
}
在之前的 Middleware 里,我们一句吧 token 里的 ID 获取到的 User 对象传递到 $request 里,现在到APP\Providers\AuthServiceProvider.php ,修改 boot() 为:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Boot the authentication services for the application.
*
* @return void
*/
public function boot()
{
$this->app['auth']->viaRequest('api', function ($request) {
// recive current user object from middleware
if ($request->auth) {
return $request->auth;
}
});
}
}
这样就可以通过 Auth::user() 获取当前用户信息。
16. make a request /auth/v2/me again: