Laravel + JWT 实现 API 跨域授权

简介配置 Laravel 5.6 + JWT + AngularJS 配置 Api 跨域授权访问,以及实现 Token 刷新。 因内容较多,涉及较广,这里只能概括的讲一下了。

安装配置

JWT

详细配置过程,请查看官方文档。

  • 安装 tymondesigns/jwt-auth composer require tymon/jwt-auth "1.0.0-rc.2"
  • 生成key php artisan jwt:secret
  • User 实现 JWTSubject 接口
  • 修改 auth.php 配置
'api' => [
            'driver' => 'jwt',
            'provider' => 'users',
        ],
  • 一个【授权 + 刷新】 的中间件 添加到 app/Http/Kernel.php
protected $routeMiddleware = [
...
 'refresh.token' => \App\Http\Middleware\RefreshToken::class
	...
	];

RefreshToken 中间件

class RefreshToken extends BaseMiddleware
{
   public function handle($request, Closure $next)
   {
       // 检查此次请求中是否带有 token,如果没有则抛出异常。
       $this->checkForToken($request);
       Log::debug($request->headers->all());
       // 使用 try 包裹,以捕捉 token 过期所抛出的 TokenExpiredException  异常
       try {
           // 检测用户的登录状态,如果正常则通过
           if ($this->auth->parseToken()->authenticate()) {
               return $next($request);
           }
           $token = $this->auth->refresh();
           // 使用一次性登录以保证此次请求的成功

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

  • 几个关键的配置
  • JWT_TTL Token的有效时间,单位:分,建议设置 20 min ~ 1 h。
  • JWT_REFRESH_TTL=1440 刷新后的 Token 有效时间,单位:分,建议设置在 7 ~ 30 day。
  • JWT_BLACKLIST_GRACE_PERIOD 防止并发请求导致某些请求失效,单位:秒,建议设置 10 ~ 60 s。

跨域

详细配置过程,请查看官方文档。

  • 安装 barryvdh/laravel-cors
  • 配置 cors 在配置文件 cors.php 中,设置 exposedHeaders,不然无法跨域获取到 header 中的 Authorization 值来刷新前端令牌。
    'exposedHeaders' => ['Authorization'],

后端 Laravel

登录

  • 登录 Api 接口 验证账号密码,返回 Token,我这里使用的 username 字段。 Api返回,自己找一个返回success、error、message 的 Trait 工具就可以了,没必要用 dingo。
class LoginController extends ApiController
{
    use AuthenticatesUsers;

    public function login(LoginRequest $request)
    {
        $credentials = $this->credentials($request);
        if ($token = auth('api')->attempt($credentials)) {
            $user = auth('api')->user();
            return $this->success(
                [
                    'user' => $user,
                    'token' => $token,
                ]);
        }
        return $this->failed('账号或密码错误!');
    }

    public function username()
    {
        return 'username';
    }
}
  • 路由 Api 接口都要使用 api 中间件,控制器最好放在 \Api 命名空间下。
Route::middleware('api')->prefix('api/user')->namespace('Modules\Account\Http\Controllers\Api')->group(function () {
			Route::post('login', 'LoginController@login')->name('user.login');
});
  • 给需要授权的接口添加中间件,比如获取用户列表 getList
 public function __construct(UserRepository $repository)
    {
        $this->middleware('refresh.token')->only([
            'getList', 'get', 'update'
        ]);
        $this->repository = $repository;
    }

前端 Angular

Token

在登录授权时,将返回的 token 存储在 TokenService 中进行管理。

this.tokenService.set({
          token: res.data.token
 });

Interceptor

拦截器将每一个请求的头中放入 Authorization 信息。

setReq(req: HttpRequest<any>, options: DelonAuthConfig): HttpRequest<any> {
    return req.clone({
      setHeaders: {
        Authorization: `Bearer ${this.model.token}`,
      },
    });
  }

Refresh Token

如果返回的 Response 的 Header 中有 Authorization 信息,说明请求中带的 Token 已经过期,服务器将 刷新的 Token 放在了 Response 头中。前端获取后更新 Token 。

 let newAuth = event.headers.get('Authorization');
      if (newAuth) {
          let token = newAuth.slice(7);
          this.tokenService.set(Object.assign(this.tokenService.get(), {
              token: token,
          }));
      }

秋叶听风
请先登录后发表评论
  • latest comments
  • 总共0条评论