Laravel5.5 -Auth middleware

[Laravel authentication Auth, custom driver, guard](https://learnku.com/articles/13434/the-laravel-framework-extends-auth-authentication-to-implement-custom-driver-g Uard) [Laravel auxiliary function auth and JWT extended explanation] (https://laravel-china.org/articles/10889/detailed-implementation-of-jwt-extensions)Copy the code

Install JWT

1. Install the software using Composer

# Composer require Tymon /jwt-auth 1.*@rcCopy the code

2. Perform some configurations

Here refers to note is that some documents will be said to add Tymon \ JWTAuth \ will \ LaravelServiceProvider: : class, this only in Laravel version 5.4 and below are necessary, updated Laravel version do not need to add.

There is also documentation about adding Tymon\JWTAuth\Providers\JWTAuthServiceProvider, which is a version of JWT from a long time ago (around 0.5.3).

2.1 Publishing the Configuration File

# this command will add a config file called PHP artisan Vendor :publish to jwt.php under config --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"Copy the code

2.2 Generating an Encryption Key

JWT_SECRET=foobar PHP artisan JWT :secret this command will generate an encryption key in the.env file, such as JWT_SECRET=foobar PHP artisan JWT :secretCopy the code

2.3 Update your model

If you use the default User table to generate tokens, you need to add a piece of code under the model

<? php namespace App; use Tymon\JWTAuth\Contracts\JWTSubject; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; Class User extends Authenticatable implements JWTSubject {use Notifiable; // Rest omitted for brevity /** * Get the identifier that will be stored in the subject claim of the JWT. * Gets the identifier token that will be stored in the JWT. * @return mixed */ public function getJWTIdentifier() { return $this->getKey(); } /** * Return a key value array containing any custom claims to be added to the JWT. * @return array */ public function getJWTCustomClaims() {return []; }}Copy the code

The above two methods are exactly what the JWTSubject interface must implement. This can also be configured according to the official document.

2.4 Register two facades

These two facades are not required, but using them will make your code a little easier.

config/app.php

'Aliases' => [... // add two lines 'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth', 'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory', ],Copy the code

If you do not use either Facade, you can use the auxiliary function Auth (” API “) instead of JWTAuth::parseToken().

2.5 modify the auth. PHP

config/auth.php

'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'jwt', JWT 'provider' => 'users',],Copy the code

2.6 Registering Some Routes

Note: Under Laravel, routes in route/api.php have prefix apis by default.

Route::group([

    'prefix' => 'auth'

], function ($router) {

    Route::post('login', 'AuthController@login');
    Route::post('logout', 'AuthController@logout');
    Route::post('refresh', 'AuthController@refresh');
    Route::post('me', 'AuthController@me');

});

Copy the code

2.7 Creating a Token Controller

php artisan make:controller AuthController
Copy the code

AuthController

Note auth(‘ API ‘)

If two facades were configured as per 2.4 above, auth(‘ API ‘) can be replaced with JWTAuth::parseToken();

<? php namespace App\Http\Controllers; use Illuminate\Support\Facades\Auth; use App\Http\Controllers\Controller; Class AuthController extends Controller {/** * Get a JWT via given credentials. * This method is used to generate tokens * @return \Illuminate\Http\JsonResponse */ public function login() { $credentials = request(['email', 'password']); if (! $token = auth('api')->attempt($credentials)) { return response()->json(['error' => 'Unauthorized'], 401); } return $this->respondWithToken($token); } /** * Get the authenticated User. * @return \Illuminate\Http\JsonResponse */ public function me() { return response()->json(auth('api')->user()); } /** * Log the user out (Invalidate the token). * * @return \Illuminate\Http\JsonResponse */ public function logout() {  auth('api')->logout(); return response()->json(['message' => 'Successfully logged out']); } /** * Refresh a token. * Refresh a token. If the blacklist is enabled, the previous token becomes invalid. * It is important to note that obtaining a Token again using the getToken above does not count as a refresh. Both tokens are obtained in parallel, i.e. both are available. * @return \Illuminate\Http\JsonResponse */ public function refresh() { return $this->respondWithToken(auth('api')->refresh()); } /** ** Get the token array structure. ** @param string $token * This method returns output information in the specified format * @return \Illuminate\Http\JsonResponse */ protected function respondWithToken($token) { return response()->json([ 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => auth('api')->factory()->getTTL() * 60 ]); }}Copy the code

Obtaining, using, deleting, and refreshing tokens

  • Here’s a postman demo,
  • Routes written to api.php in Laravel have prefix apis by default

1.1 access token

1.2 use the token

There are two ways to use it:

  • Add to url:? Token = your token
  • Add to header. This is recommended because it is more secure in HTTPS:Authorization: Bearer your token

1.3 delete the token

After the token is deleted, the token becomes invalid and cannot be used to obtain data.

1.4 the refresh token

3. Token refresh

If the token is not refreshed, then the token is equivalent to the above user name + password. As long as the token is obtained, it can always be stolen. Therefore, it is necessary to set the validity period and refresh the token. The longer the validity period, the higher the risk, the shorter the validity, the higher the refresh frequency, and the refresh cost.

A token typically has three time attributes, all of which are configured in config/jwt.php.

Valid time

The validity period refers to how long you can use the token to access content after you have acquired it.

// unit: minute 'TTL' => env('JWT_TTL', 60)Copy the code

The refresh time

Refresh time refers to the time during which the old token can be exchanged for a new token. For example, if the validity period of the token is 60 minutes and the refresh period is 20160 minutes, you can obtain a new token using this token within 60 minutes but cannot obtain a new token after 60 minutes. Then, you can obtain a new token repeatedly until the total time exceeds 20160 minutes.

// unit: minute 'refresh_TTL' => env('JWT_REFRESH_TTL', 20160)Copy the code

Grace time

The grace period is used to solve the problem of concurrent requests. If the grace period is 0s, concurrent requests will fail during the transfer of the old and new tokens. Therefore, you need to set a grace period

// Set the grace period (unit: Env ('JWT_BLACKLIST_GRACE_PERIOD', 60)Copy the code

What if the token expires after the default 60 minutes?

Create a middleware to refresh the token

 art make:middleware RefreshToken 
Copy the code

Create a middleware to refresh the token

<? php namespace App\Http\Middleware; use Closure; use Tymon\JWTAuth\Facades\JWTAuth; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Exceptions\TokenExpiredException; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; use Tymon\JWTAuth\Http\Middleware\BaseMiddleware; class RefreshToken extends BaseMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, $this->checkForToken($request) $this->checkForToken($request); $this->checkForToken($request); If ($request->user = $request->user = $request->user = $request->user = $request->user = $request->user = JWTAuth::parseToken()->authenticate()) { return $next($request); } throw new UnauthorizedHttpException (' JWT - auth ', 'not login'); } catch (TokenExpiredException $exception) {try {// Get the expired token, refresh the token, set the token and validate the token JWTAuth::refresh(JWTAuth::getToken()); JWTAuth::setToken($token); $request->user = JWTAuth::authenticate($token); $request->headers->set('Authorization', 'Bearer ' . $token); // After the token is refreshed, } Catch (JWTException $exception) {throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage()); Return $this->setAuthenticationHeader($next($request), $token); } public function checkForToken($request) { $token = $request->header('Authorization'); If (empty ($token)) {throw new UnauthorizedHttpException (' JWT - auth ', "unauthorised access"); }}}Copy the code

Register middleware in Kernel

/** * The application's route middleware. * * These middleware may be assigned to groups or used individually. * * @var array */ protected $routeMiddleware = [ ...... 'token.refresh' => \App\Http\Middleware\RefreshToken::class, / / token. Refresh,];Copy the code

Apply middleware in Routes/API

  Route::post('auth/login', 'AuthController@login');
Route::middleware('token.refresh')->group(function () {
    Route::post('auth/logout', 'AuthController@logout');
    Route::post('auth/refresh', 'AuthController@refresh');
    Route::post('auth/me', 'AuthController@me');
});
Copy the code

The new token returned to the header needs to be listened on by the front end. If the front end is replaced, the new token needs to be replaced in every request.

Use with Swoole with caution

Swoole will cache auth singleton. If swoole is enabled, Auth (‘ API ‘) will fail to obtain the JWT driver and report an error. The Auth singleton cache needs to be cleared before each routing request.

Add JWT service providers to config/laravels. Config

'register_providers' => [ App\Providers\AuthServiceProvider::class, Tymon \ JWTAuth \ will \ LaravelServiceProvider: : class, / / registered JWT provider, Illuminate, Session, SessionServiceProvider: : class, \Illuminate\Pagination\PaginationServiceProvider::class, ],Copy the code

Clean up auth singleton in eventServiceProvides. PHP

Event::listen('laravels.received_request', function (\Illuminate\Http\Request $req, $app) {            Facade::clearResolvedInstance('auth');        });        parent::boot();
Copy the code