通过 Passport 实现 API 请求认证:第三方应用篇(授权码获取令牌)
上一篇教程我们主要介绍了公司自有系统之间如何通过用户凭证获取授权码访问认证 API 接口,如果我们自己也是一个开放平台,需要支持第三方应用户接入获取认证信息呢?比如我们常见的第三方应用接入微信登录、微博登录、QQ 登录就是这样的例子。我们把自己的系统比作微信、微博这样的平台,支持第三方 App、网站应用的接入,这个时候如果还像上篇教程介绍的那样访问认证资源,就有安全隐患了,如果第三方应用不可信,把用户名密码信息记录下来,这就泄露了用户的密码数据,肯定是用户和平台都不愿看到的,所以面对这种场景,我们今天介绍另外一种 OAuth 认证方式 —— 通过授权码的方式获取令牌访问认证 API。
这篇教程里,我们把待接入的第三方应用看作前端系统,把自己的平台看作后端系统,跟上篇教程一样,在后端系统注册前端应用后才能处理对前端请求的授权,然后我们在前端系统编写认证视图,用户点击访问认证资源并确认授权后,前端系统才能获取令牌对后端认证 API 接口进行访问。
1、在后端系统注册第三方应用
我们还是在上一篇教程创建的 testapp
应用基础上进行测试,并且在后端系统通过 Artisan 命令 passport:client
新注册这个第三方应用:
学院君注:当然对于大型平台来说,肯定需要设计一整套第三方应用注册、审核流程来完成应用接入。这里简化为通过命令一键注册,原理是一样的,接入方式不同而已。
2、配置第三方应用
接下来,我们回到前端系统,修改 testapp
根目录下 .env
中的 CLIENT_ID
和 CLIENT_SECRET
配置项:
CLIENT_ID=9
CLIENT_SECRET=Xde5hsAbpEU8MMjwELFh6RNOzxX2LsrxgFTZvXkP
config/services.php
中的配置保持和上篇教程一样不变。
3、编写第三方应用路由和控制器
要通过授权码获取访问令牌,需要两步操作,第一步是到后端系统请求授权,如果用户在后端系统没有登录需要先登录,登录之后让用户确认授权,授权之后通过 callback
配置的跳转地址回跳到前端应用,并且在 URL 中带上授权码,然后用户再通过这个授权码获取访问令牌,拿到访问令牌之后就可以请求后端系统认证 API 接口了。
所以,我们需要在前端应用的 routes/web.php
中新增两个路由,一个用于请求授权获取授权码,一个用于从后端应用跳转回来,通过授权码在回跳路由中发起后端请求获取令牌:
Route::get('/auth', 'Auth\LoginController@oauth');
Route::get('/auth/callback', 'Auth\LoginController@callback');
然后定义相应的控制器方法:
public function oauth()
{
$query = http_build_query([
'client_id' => config('services.blog.appid'),
'redirect_uri' => config('services.blog.callback'),
'response_type' => 'code',
'scope' => '',
]);
return redirect('http://blog.test/oauth/authorize?'.$query);
}
public function callback(Request $request)
{
$code = $request->get('code');
if (!$code) {
dd('授权失败');
}
$http = new Client();
$response = $http->post('http://blog.test/oauth/token', [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => config('services.blog.appid'), // your client id
'client_secret' => config('services.blog.secret'), // your client secret
'redirect_uri' => config('services.blog.callback'),
'code' => $code,
],
]);
return response($response->getBody());
}
4、测试通过授权码获取令牌
在浏览器中访问 http://app.test/auth
,在前端应用中通过后端系统进行授权认证,如果你在后端应用 blog.test
上没有登录,先跳转到登录页面,登录之后则跳转到如下确认授权页面:
点击绿色的授权按钮,就可以跳转到前端应用回调路由,然后发起获取令牌请求获取访问令牌了:
这样,下次从前端应用 app.test
中访问后端系统 API 接口时,就可以通过在请求头中带上 access_token
来获取 blog.test
上的认证资源了,对应的逻辑和上一篇通过密码获取令牌访问是一样的。
通过 Postman 进行测试,将 access_token
值拷贝到下面的 Token 字段,然后发起对认证 API 接口 http://blog.test/api/user
的请求,结果完全一样:
令牌的有效期和刷新逻辑和上一篇密码授权令牌一样,这里也不再赘述了。
下一篇我们将围绕开发平台上入驻的个人开发者授权令牌与认证展开讨论。
8 Comments
return redirect('http://blog.test/oauth/authorize?'.$query);
这个回掉路由的处理,是再哪个控制器呢?测试不行啊知道了 执行
php artisan route:list
就可以看到了。但是我还是会报错Undefined property: App\Http\Middleware\Authenticate::$redirectTo
,不知道怎么处理登陆后提示 {"error":"invalid_client","error_description":"Client authentication failed","message":"Client authentication failed"} 是什么情况?
确保table oauth_clients中的personal_access_client和password_client字段均为0
确保table oauth_clients中的personal_access_client和password_client字段均为0 否则会报{"error":"invalid_client","error_description":"Client authentication failed","message":"Client authentication failed"}
我测试的报这个错误:Client error:
POST http://blog.com/oauth/token
resulted in a401 Unauthorized
response: 你知道是什么原因吗点击授权后,返回 400 Bad Request,错误显示是‘缺少必要的参数,或包含不必要的参数’
注意自己在主应用中注册时,生成的: CLIENT_ID=4 CLIENT_SECRET=HClxhvsWgmXxWixypeR6aM0jBmyiediV9EDwerw 在移动端应用中是否配置正确