编程学习网 > PHP技术 > laravel > laravel配合jwt-auth 进行接口开发,防止并发
2021
07-28

laravel配合jwt-auth 进行接口开发,防止并发

1、按照官网进行下载。 这里我使用的laravel 是5.5   jwt-auth 推荐我们下载1.0 的版本 因为原来的版本有问题。

如果你是直接用过composer  require  tymon/jwt-auth   这里下载的可能是0.5的版本

composer  require  tymon/jwt-auth //下载的是0.5的版本

composer require tymon/jwt-auth 1.0.0-rc.1  这里下载的就是  最新版本的

2、如果你的laravel  是5.4 或者更低版本的话,那么就需要在provider 里面进行注册

将服务提供者添加到配置文件中的providers数组中config/app.php,如下所示:


'providers' => [

   ...

   Tymon\JWTAuth\Providers\LaravelServiceProvider::class,

]


3、运行以下命令发布包配置文件:


php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"


你现在应该有一个config/jwt.php文件,允许你配置这个包的基础知识。


4、生成密钥

jwt-auth 已经预置了一个 Artisan 命令 直接使用下面的命令  只需要运行shell 命令就可以了


php artisan jwt:secret

然后结果会在.env 的文件中新增一行   JWT_SECRET=secret


5、配置 Auth guard

因为这里我们直接使用的是jwt 的验证,所以我们就不用他自己带的权限了所以在下面进行修改。

在 config/auth.php 文件中,你需要将 guards/driver 更新为 jwt:

auth.php


'defaults' => [

   'guard' => 'api',

   'passwords' => 'users',

],

...

'guards' => [

   'api' => [

       'driver' => 'jwt',

       'provider' => 'users',

   ],

],


只有在使用 Laravel 5.2 及以上版本的情况下才能使用


6、如果需要使用jwt-auth 作为用户认证,我们需要对我们的 user 模型进行修改。

这个是系统自带的user.php 模型


<?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.

    *

    * @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 [];

   }

}


7、先创建一个中间件。RefreshToken

先来说明一下我想要达成的效果,我希望用户提供账号密码前来登录。如果登录成功,那么我会给前端颁发一个 access _token ,设置在 header 中以请求需要用户认证的路由。

同时我希望如果用户的令牌如果过期了,可以暂时通过此次请求,并在此次请求中刷新该用户的 access _token,最后在响应头中将新的 access _token 返回给前端,这样子可以无痛的刷新 access _token ,用户可以获得一个很良好的体验,所以开始动手写代码。

执行如下命令以新建一个中间件:  中间件生成之后会在app/Http/Middleware/RefreshToken.php


php artisan make:middleware RefreshToken

中间件代码如下:

RefreshToken.php


<?php

namespace App\Http\Middleware;

use Auth;

use Closure;

use Tymon\JWTAuth\Exceptions\JWTException;

use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;

use Tymon\JWTAuth\Exceptions\TokenExpiredException;

use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

// 注意,我们要继承的是 jwt 的 BaseMiddleware

class RefreshToken extends BaseMiddleware

{

   /**

    * Handle an incoming request.

    *

    * @param  \Illuminate\Http\Request $request

    * @param  \Closure $next

    *

    * @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException

    *

    * @return mixed

    */

   public function handle($request, Closure $next)

   {

       // 检查此次请求中是否带有 token,如果没有则抛出异常。

       $this->checkForToken($request);

      // 使用 try 包裹,以捕捉 token 过期所抛出的 TokenExpiredException  异常

       try {

           // 检测用户的登录状态,如果正常则通过

           if ($this->auth->parseToken()->authenticate()) {

               return $next($request);

           }

           throw new UnauthorizedHttpException('jwt-auth', '未登录');

       } catch (TokenExpiredException $exception) {

         // 此处捕获到了 token 过期所抛出的 TokenExpiredException 异常,我们在这里需要做的是刷新该用户的 token 并将它添加到响应头中

           try {

               // 刷新用户的 token

               $token = $this->auth->refresh();

              // 使用一次性登录以保证此次请求的成功

               Auth::guard('api')->onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']);

           } catch (JWTException $exception) {

              // 如果捕获到此异常,即代表 refresh 也过期了,用户无法刷新令牌,需要重新登录。

               throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage());

           }

       }

       // 在响应头中返回新的 token

       return $this->setAuthenticationHeader($next($request), $token);

   }

}


生成完成之后需要将中间件进行注册,不然后面会报错

在app/Http/Middleware/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,

       'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,

       'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,

         //下面这个就是我自己进行添加的内容

       'RefreshToken'=> \App\Http\Middleware\RefreshToken::class,

   ];


8、接下来配置路由


<?php

use Illuminate\Http\Request;

/*

|--------------------------------------------------------------------------

| API Routes

|--------------------------------------------------------------------------

|

| Here is where you can register API routes for your application. These

| routes are loaded by the RouteServiceProvider within a group which

| is assigned the "api" middleware group. Enjoy building your API!

|

*/

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

//    return $request->user();

//});

Route::group(['prefix'=>'auth'],function($route){

   Route::post('login','AuthController@login')->name('login');

   Route::post('logout','AuthController@logout');

});

Route::group(['middleware'=>'RefreshToken','prefix'=>'auth'],function($route){

       Route::post('refresh','AuthController@refresh');

       Route::post('me','AuthController@me');

       Route::post('test','AuthController@test');

});


9、然后我们创建AuthController.php

php artisan make:controller AuthController

打开控制器,写入以下内容


<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Auth;

use App\Http\Controllers\Controller;

use Illuminate\Http\Request;

class AuthController extends Controller

{

   //

   public function login(Request $request)

   {

       //这里我只接受email 和 password

       $credentials = $request->only(['email','password']);

          //通过jwt进行验证。如果成功就会返回token 如果不通过就401错误

       if (! $token = Auth::guard('api')->attempt($credentials)) {

           return response()->json(['error' => 'Unauthorized'], 401);

       }

       return $this->respondWithToken($token);

   }

   public function test(){

       echo 'ccc';

   }

       //验证我们需要接收的参数

       //if(){}

       //如果验证成功就直接返回token

   protected function respondWithToken($token)

   {

       return response()->json([

           'access_token' => $token,

           'token_type' => 'bearer',

           //这里注意以下,我设置的时间是1分钟过期

           'expires_in' => auth()->factory()->getTTL()

       ]);

   }

   //退出登录

   public function logout(){

       //退出登录,并且销毁token

       Auth::guard('api')->logout();

       return response(['message'=>'退出成功']);

   }

}


10、可以使用laravel 自身的数据表

php artisan migrate

11、jwt.php 配置文件的详细解释


<?php

return [

   /*

   | JWT Authentication Secret

   | 用于加密生成 token 的 secret

   */

   'secret' => env('JWT_SECRET'),

   /*

   |--------------------------------------------------------------------------

   | JWT Authentication Keys

   |--------------------------------------------------------------------------

   |

   | 如果你在 .env 文件中定义了 JWT_SECRET 的随机字符串

   | 那么 jwt 将会使用 对称算法 来生成 token

   | 如果你没有定有,那么jwt 将会使用如下配置的公钥和私钥来生成 token

   |

   */

   'keys' => [

       /*

       |--------------------------------------------------------------------------

       | Public Key

       |--------------------------------------------------------------------------

       |

       | 公钥

       |

       */

       'public' => env('JWT_PUBLIC_KEY'),

       /*

       |--------------------------------------------------------------------------

       | Private Key

       |--------------------------------------------------------------------------

       |

       | 私钥

       |

       */

       'private' => env('JWT_PRIVATE_KEY'),

       /*

       |--------------------------------------------------------------------------

       | Passphrase

       |--------------------------------------------------------------------------

       |

       | 私钥的密码。 如果没有设置,可以为 null。

       |

       */

       'passphrase' => env('JWT_PASSPHRASE'),

   ],

   /*

   |--------------------------------------------------------------------------

   | JWT time to live

   |--------------------------------------------------------------------------

   |

   | 指定 access_token 有效的时间长度(以分钟为单位),默认为1小时,您也可以将其设置为空,以产生永不过期的标记

   |

   */

   //这里默认的是60分钟,我为了测试将时间修改为1分钟。

  // 'ttl' => env('JWT_TTL', 60),

     'ttl' => env('JWT_TTL', 1),

   /*

   |--------------------------------------------------------------------------

   | Refresh time to live

   |--------------------------------------------------------------------------

   |

   | 指定 access_token 可刷新的时间长度(以分钟为单位)。默认的时间为 2 周。

   | 大概意思就是如果用户有一个 access_token,那么他可以带着他的 access_token

   | 过来领取新的 access_token,直到 2 周的时间后,他便无法继续刷新了,需要重新登录。

   |

   */

   'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),

   /*

   |--------------------------------------------------------------------------

   | JWT hashing algorithm

   |--------------------------------------------------------------------------

   |

   | 指定将用于对令牌进行签名的散列算法。

   |

   */

   'algo' => env('JWT_ALGO', 'HS256'),

   /*

   |--------------------------------------------------------------------------

   | Required Claims

   |--------------------------------------------------------------------------

   |

   | 指定必须存在于任何令牌中的声明。

   |

   |

   */

   'required_claims' => [

       'iss',

       'iat',

       'exp',

       'nbf',

       'sub',

       'jti',

   ],

   /*

   |--------------------------------------------------------------------------

   | Persistent Claims

   |--------------------------------------------------------------------------

   |

   | 指定在刷新令牌时要保留的声明密钥。

   |

   */

   'persistent_claims' => [

       // 'foo',

       // 'bar',

   ],

   /*

   |--------------------------------------------------------------------------

   | Blacklist Enabled

   |--------------------------------------------------------------------------

   |

   | 为了使令牌无效,您必须启用黑名单。

   | 如果您不想或不需要此功能,请将其设置为 false。

   |

   */

   'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),

   /*

   | -------------------------------------------------------------------------

   | Blacklist Grace Period

   | -------------------------------------------------------------------------

   |

   | 当多个并发请求使用相同的JWT进行时,

   | 由于 access_token 的刷新 ,其中一些可能会失败

   | 以秒为单位设置请求时间以防止并发的请求失败。

   |

   */

   'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0),

   /*

   |--------------------------------------------------------------------------

   | Providers

   |--------------------------------------------------------------------------

   |

   | 指定整个包中使用的各种提供程序。

   |

   */

   'providers' => [

       /*

       |--------------------------------------------------------------------------

       | JWT Provider

       |--------------------------------------------------------------------------

       |

       | 指定用于创建和解码令牌的提供程序。

       |

       */

       'jwt' => Tymon\JWTAuth\Providers\JWT\Namshi::class,

       /*

       |--------------------------------------------------------------------------

       | Authentication Provider

       |--------------------------------------------------------------------------

       |

       | 指定用于对用户进行身份验证的提供程序。

       |

       */

       'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,

       /*

       |--------------------------------------------------------------------------

       | Storage Provider

       |--------------------------------------------------------------------------

       |

       | 指定用于在黑名单中存储标记的提供程序。

       |

       */

       'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,

   ],

];


12、测试结果

1、使用postman 进行测试


2、使用token 进行验证

3、过期刷新token  这个时候token 已经过期了  因为我设置的是1分钟,同时会在Headers 中返回一个头信息authorization →Bearer  然后会带着一个token  返回给前端,这个时候前端需要将新的token  存放在本地localStorage 中,下次的时候带着一起过来就可以了。这块的内容 会在后期vue的内容中进行更新

注意:

1、这里我设置的token 1分钟过期。那么我们在请求的过程中token是变化的。

2、如果在使用postman测试的过程中,出现 The token has been blacklisted in file   可能出现的原因是你的token 已经被销毁,因为我们生成新的token 之后如果还使用原来的token 就会被拒绝访问。

3、还需要注意的是目前使用的表是users 表  如果是其他的表,那么需要在guards 那里进行修改。

4、访问的url 地址需要注意一下: 因为我们的路由是在api.php  中写的,同时我们设置的前缀是auth

'prefix'=>'auth'  所以我们的访问地址是   admin.ttshop.com/api/auth/login     这里的prefix 我们可以设置为V1、V2、V3这样的话 也就是不同版本的内容了。admin.ttshop.com/api/v1/login    admin.ttshop.com/api/v2/login

5、最后我们在登录成功之后每次访问需要携带token 如果不带token 则会报错。

以上就是“laravel 配合 jwt-auth 进行接口开发”的详细内容,想要获取更多laravel教程欢迎关注编程学习网

扫码二维码 获取免费视频学习资料

Python编程学习

查 看2022高级编程视频教程免费获取