Laravel Passport中使用JSON API形式的code授权模式小结
介绍
业务需要开发账号系统,所以在Laravel中使用passport。使用密码授权模式进行前台用户的登录时合格的,但是在开发Oauth的第三方服务的时候,发现授权码模式有一些坑,最后通宵解决了,因此做如下记录
授权码模式的配置
1.在config/auth.php
文件中,将web的验证驱动修改为passport
第一个坑:虽然文档上说可以直接将地址重定向,但是在跳转时还是会有验证,因为之前使用密码授权模式并且使用token。所以驱动改为passport后,授权码模式的相关接口将会使用和账号密码一样的验证方式
'guards' => [
'web' => [
'driver' => 'passport',
'provider' => 'users',
],
2.在使用passort驱动后,需要编写一个路由中间件,在Kernel.php文件中在所有请求前使用。
因为之前使用的json api的验证方式,token需卸载header里面才能通过验证,但是在页面重定向时无法设置hader头信息。
因为passport的验证也是通过中间件来进行的,并且他们的读取也是通过Laravel的Request类来读取header信息,因此写一个中间件去读取query string里面的tokn信息并设置到header里面,并放在所有中间件之前运行即可像之前密码授权方式一样通过验证。
class DealToken
{
/**
* 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)
{
$request = app(Request::class);
if ($request->has('access_token')) {
$request->headers->set('Authorization','Bearer '.$request->get('access_token'));
}
return $next($request);
}
}
3.创建Client模型,设置为passport使用的客户端模型,并重写方法skipsAuthorization
恒定返回true来跳过授权确认页面
按照文档中的流程,是先重定向到一个页面后点击授权。那么会遇到两个问题
- 整个过程会经历两个接口:
GET /oauth/authorize
和POST /oauth/authorize
。但是在这个过程中,上面一步的token在两个接口调用的过程中是不会被传递的。 - 不能直接使用
POST /oauth/authorize
方法,因为passport在第一个接口中会在session中存入authrequest的数据,并且在第二个接口去验证
因此重写该方法跳过授权页面,在GET /oauth/authorize
时不会显示授权页面而是直接执行POST /oauth/authorize
并进行跳转
在AuthServiceProvider
设置客户端模型
Passport::useClientModel(ClientsModel::class);
创建Client模型,重写skipsAuthorization
方法
<?php
namespace App\Models\Passport;
use Laravel\Passport\Client as BaseClient;
class Client extends BaseClient
{
/**
* 确定客户端是否应跳过授权提示。
*
* @return bool
*/
public function skipsAuthorization()
{
return $this->firstParty();
}
}
4.最后再开发授权登录页面以及通过code换取token的接口就完成了
code模式认证流程
1.重定向到授权登录页面让用户登录
2.登录成功就重定向到GET /oauth/authorize
,除了携带指定参数外,还需使用get方式传递第一步登录获取的token
3.页面会重定向到Client中的redirect的地址并携带code
3.第三方会在redirect页面接受code并处理,携带code调用对应接口换取token,该接口也会返回用户唯一标识guid
总结
目前国内的网上有很多文档因为版本的更新或者没关注这个地方,从而导致文档的正确性出现问题,因此遇到和文档不符的时候可以大胆尝试,如解决不了可以去通过google或者stack overflow寻求帮助。