最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 如何在Laravel集成JWT(API访问授权)

    正文概述 转载于:掘金(秋狄南)   2021-01-06   457

    参考文档:Laravel5.5源码详解--Auth中间件

              [Laravel认证Auth,自定义driver,guard](https://learnku.com/articles/13434/the-laravel-framework-extends-auth-authentication-to-implement-custom-driver-guard)             
    
              [Laravel 辅助函数 auth 与 JWT 扩展详解](https://laravel-china.org/articles/10889/detailed-implementation-of-jwt-extensions)
    

    一、安装JWT

    1. 使用 composer 安装

    # 使用1.0以上版本
    composer require tymon/jwt-auth 1.*@rc
    

    2. 进行一些配置

    这里指的注意的是,有些文档会说要添加 Tymon\JWTAuth\Providers\LaravelServiceProvider::class,这只在 Laravel 5.4 及以下版本是必要的,更新的 Laravel 版本无需添加。

    还有一些文档说要添加 Tymon\JWTAuth\Providers\JWTAuthServiceProvider 这是很久以前的 JWT 版本的(大概0.5.3 以前的版本)。

    2.1 发布配置文件

    # 这条命令会在 config 下增加一个 jwt.php 的配置文件
    php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
    

    2.2 生成加密密钥

    # 这条命令会在 .env 文件下生成一个加密密钥,如:JWT_SECRET=foobar
    php artisan jwt:secret
    

    2.3 更新你的模型

    如果你使用默认的 User 表来生成 token,你需要在该模型下增加一段代码

    <?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.
         * 获取将存储在JWT的中的标识符token。
         * @return mixed
         */
        public function getJWTIdentifier()
        {
            return $this->getKey();
        }
    
        /**
         * Return a key value array, containing any custom claims to be added to the JWT.
         * 返回一个键值数组,其中包含要添加到JWT中的任何自定义声明
         * @return array
         */
        public function getJWTCustomClaims()
        {
            return [];
        }
    }
    

    上面两个方法,其实就是实现了JWTSubject接口必须实现的方法。这个也是按照官方文档进行配置即可。

    2.4 注册两个 Facade

    这两个 Facade 并不是必须的,但是使用它们会给你的代码编写带来一点便利。

    config/app.php

    'aliases' => [
            ...
            // 添加以下两行
            'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth',
            'JWTFactory' => 'Tymon\JWTAuth\Facades\JWTFactory',
    ],
    

    如果你不使用这两个 Facade,你可以使用辅助函数 auth(“api”)来替代JWTAuth::parseToken()。

    2.5 修改 auth.php

    config/auth.php

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    
        'api' => [
            'driver' => 'jwt',      // 原来是 token 改成jwt
            'provider' => 'users',
        ],
    ],
    

    2.6 注册一些路由

    注意:在 Laravel 下,route/api.php 中的路由默认都有前缀 api

    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');
    
    });
    
    

    2.7 创建 token 控制器

    php artisan make:controller AuthController
    

    AuthController

    值得注意的是 auth('api') 

    如果按照上面2.4配置了两个facade,可以使用JWTAuth::parseToken()替换auth('api');

    <?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.
         * 该方法用于生成token
         * @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.
         * 该方法通过token获取对应的用户信息
         * @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.
         * 刷新token,如果开启黑名单,以前的token便会失效。
         * 值得注意的是用上面的getToken再获取一次Token并不算做刷新,两次获得的Token是并行的,即两个都可用。
         * @return \Illuminate\Http\JsonResponse
         */
        public function refresh()
        {
            return $this->respondWithToken(auth('api')->refresh());
        }
    
        /**
         * Get the token array structure.
         *
         * @param  string $token
         * 该方法按照指定的格式返回输出信息
         * @return \Illuminate\Http\JsonResponse
         */
        protected function respondWithToken($token)
        {
            return response()->json([
                'access_token' => $token,
                'token_type' => 'bearer',
                'expires_in' => auth('api')->factory()->getTTL() * 60
            ]);
        }
    }
    

    二. token 的获取、使用、删除和刷新

    • 以下用 postman 演示,
    • Laravel 环境下写在 api.php 中的路由默认有前缀 api

    1.1 获取 token

    如何在Laravel集成JWT(API访问授权)

    1.2 使用 token

    有两种使用方法:

    • 加到 url 中:?token=你的token
    • 加到 header 中,建议用这种,因为在 https 情况下更安全:Authorization:Bearer 你的token

    如何在Laravel集成JWT(API访问授权)

    1.3 删除 token

    如何在Laravel集成JWT(API访问授权)

    删除 token 后,token就会失效,无法再利用其获取数据。

    1.4 刷新 token

    如何在Laravel集成JWT(API访问授权)

    三、Token的刷新

    如果 token 不刷新,那么 token 就相当于上面的用户名 + 密码,只要获取到了,就可以一直盗用,因此 token 设置有效期并能够进行刷新是必要的。有效期越长,风险性越高,有效性越短,刷新频率越高,刷新就会存在刷新开销。

    一个 token 一般来说有三个时间属性,其配置都在 config/jwt.php 内。

    有效时间

    有效时间指的的是你获得 token 后,在多少时间内可以凭这个 token 去获取内容,逾时无效。

    // 单位:分钟
    'ttl' => env('JWT_TTL', 60)
    

    刷新时间

    刷新时间指的是在这个时间内可以凭旧 token 换取一个新 token。例如 token 有效时间为 60 分钟,刷新时间为 20160 分钟,在 60 分钟内可以通过这个 token 获取新 token,但是超过 60 分钟是不可以的,然后你可以一直循环获取,直到总时间超过 20160 分钟,不能再获取。

    // 单位:分钟
    'refresh_ttl' => env('JWT_REFRESH_TTL', 20160)
    

    宽限时间

    宽限时间是为了解决并发请求的问题,假如宽限时间为 0s ,那么在新旧 token 交接的时候,并发请求就会出错,所以需要设定一个宽限时间,在宽限时间内,旧 token 仍然能够正常使用

    // 宽限时间需要开启黑名单(默认是开启的),黑名单保证过期token不可再用,最好打开
    'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true)
    
    // 设定宽限时间,单位:秒
    'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 60)
    

    那么token在默认的60分钟后过期了怎么办呢?

    创建一个中间件用来刷新token

     art make:middleware RefreshToken 
    

    创建一个中间件用来刷新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, Closure $next)
        {
            //检查请求中是否带有token 如果没有token值则抛出异常
            $this->checkForToken($request);
            try {
                //从请求中获取token并且验证token是否过期  若是不过期则请求到控制器处理业务逻辑  若是过期则进行刷新
                if ($request->user = JWTAuth::parseToken()->authenticate()) {
                    return $next($request);
                }
                throw new UnauthorizedHttpException('jwt-auth', '未登录');
            } catch (TokenExpiredException $exception) {
                try {
                    //首先获得过期token 接着刷新token 再接着设置token并且验证token合法性
                    $token = JWTAuth::refresh(JWTAuth::getToken());
                    JWTAuth::setToken($token);
                    $request->user = JWTAuth::authenticate($token);
                    $request->headers->set('Authorization', 'Bearer ' . $token); // token被刷新之后,保证本次请求在controller中需要根据token调取登录用户信息能够执行成功
                } catch (JWTException $exception) {
                    throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage());
                }
            }
            //将token值返回到请求头
            return $this->setAuthenticationHeader($next($request), $token);
        }
    
        public function checkForToken($request)
        {
            $token = $request->header('Authorization');
            if (empty($token)) {
                throw new UnauthorizedHttpException('jwt-auth', "未授权访问");
            }
        }
    }
    

    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、
      ];
    

    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');
    });
    

    如何在Laravel集成JWT(API访问授权)

    返回到header中新的token需要前端去监听,如果更换了前端每次请求中要换上这个新的token。

    四、与Swoole一起用需要注意

    swoole会缓存auth单例,开启swoole后,auth('api')会获取不到jwt驱动而报错,需要在每次路由请求前清除auth单例缓存,操作如下:

    config/laravels.config中添加jwt服务提供者

       'register_providers'       => [
            App\Providers\AuthServiceProvider::class,
            Tymon\JWTAuth\Providers\LaravelServiceProvider::class,//注册jwt提供者
            \Illuminate\Session\SessionServiceProvider::class,
            \Illuminate\Pagination\PaginationServiceProvider::class,
        ],
    

    eventServiceProvides.php中清理auth单例

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

    起源地下载网 » 如何在Laravel集成JWT(API访问授权)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元