API Authentication (Passport) 初体验
laravel 的 api 路由默认写了一个 api
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
如果直接访问 /api/user 会重定向到登录页,已登录的也不会正常显示需要的数据,这是因为需要 api 授权认证才能正常访问。
为了让服务器支持 API 授权,体验了一把 Passport OAuth 认证,把初次使用这个的过程整理记录一下,也给其它初学者一些经验。
正常的 oauth 授权流程应该是这样:
(A)用户访问客户端,后者将前者导向认证服务器。
(B)用户选择是否给予客户端授权。
(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的 "重定向 URI"(redirection URI),同时附上一个授权码。
(D)客户端收到授权码,附上早先的 "重定向 URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
(E)认证服务器核对了授权码和重定向 URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
从流程可知 oauth 授权是需要客户端和服务端二个网站,这里只使用了一个网站:laravel.test
,没有使用二个网站来模拟发送请求和授权,基本自己写的路由都是客户端的,服务端不用写啥。
安装#
这个完全根据说明文档操作就行,没有任何难度,应该也不会出现任何意外。
composer require laravel/passport
php artisan migrate
php artisan passport:install
安装完成,数据库会生成几张 oauth 前缀的数据表,在 storage
目录下生成 oauth-private.key
和 oauth-public.key
二个文件,同时会生成二条 oauth client 数据。
前端快速上手#
为了方便体验,服务端用户认证系统这里就直接用框架自带的,先安装上:
php artisan make:auth
php artisan migrate
前端使用到 Vue 组件:
php artisan vendor:publish --tag=passport-components
当组件被发布后,按文档在 resources/assets/js/app.js
文件中注册它们,这里我们把认证管理的三个 Vue 组件放到用户认证系统自带的 home.blade.php
中。
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Dashboard</div>
<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif
<passport-clients></passport-clients>
<passport-authorized-clients></passport-authorized-clients>
<passport-personal-access-tokens></passport-personal-access-tokens>
</div>
</div>
</div>
</div>
</div>
@endsection
我们要配置好前端环境,直接 yarn
安装前端组件,然后 npm run dev
。
注册一个用户登录看看:
配置#
发放令牌有指令或客户端两种方式,我们已经使用 vue 组件快速建了客户端,直接点 Create New Client
来自己建个。
请求令牌#
向服务端应用程序的 /oauth/authorize
路由发出请求,网址参数如下:
这里也按文档写一个路由,然后访问 http://laravel.test/redirect 请求令牌:
Route::get('/redirect', function () {
$query = http_build_query([
'client_id' => '3',
'redirect_uri' => 'http://laravel.test/callback',
'response_type' => 'code',
'scope' => '',
]);
return redirect('http://laravel.test/oauth/authorize?'.$query);
});
第一次请求时会提示是否授权:
确定授权后,服务端会重定向到回调网址,并传回授权码 code。
将授权码转换为访问令牌#
文档中是直接在回调路由中使用授权码,换 token,这一步需要使用到 client_Secret
:
Route::get('/callback', function (\Illuminate\Http\Request $request) {
$http = new GuzzleHttp\Client;
$response = $http->post('http://laravel.test/oauth/token', [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => '3',
'client_secret' => 'SlxvmfrYl9cRmJpsbojrksfMw8VHUhsZgEpfoc2l',
'redirect_uri' => 'http://laravel.test/callback',
'code' => $request->code,
],
]);
return json_decode((string)$response->getBody(), true);
});
使用 id 、secret、code 等换到 token:
现在拿到 token 了,我们再来访问 /api/user 试试,写个路由用 token 向服务端请求数据:
Route::get('/api-test', function (){
$client = new GuzzleHttp\Client;
$accessToken = "eyJ0eXAiOiJKV1QiLCJhbG*******6cbwIlrI";
$response = $client->request('GET', 'http://laravel.test/api/user', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$accessToken,
],
]);
return json_decode((string)$response->getBody(), true);
});
客户端访问 http://laravel.test/api-test 试试,正常返回结果啦~
文档中获取授权的 token 有4种模式,结合这篇文档应该能更好的理解:
http://www.ruanyifeng.com/blog/2014/05/oau...
除了密码授权令牌和直接生成个人 Token 外,其它授权模式都需要用户登录确定授权。关于直接生成个人令牌的方式,注意图中有一个 Personal Access Tokens
,在客户端直接生成个人 Token(不足的是不能设置 scope 权限范围), 但可以直接使用,不需要用授权码换。
为了区分,这里换一个用户登录,然后直接生成 Token:
用这个 token 再授权访问 /api/user
试试:
正常取得用户资料,完美~
在流程测试中以下网址是客户端请求方的,其它全是服务端的。
http://laravel.test/redirect 生成请求授权码的链接用
http://laravel.test/callback 请求回调网址,用来把授权码换成 Token 令牌
http://laravel.test/api-test 身份验证并请求服务端 api (/api/user) 的数据
服务端认证路由全部是 Passport::routes();
注册的,具体路由可以看 vendor/laravel/passport/src/RouteRegistrar.php
其他功能这里就不演示了,只能说很好很强大~
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: