手摸手,教你使用 laravel-passport 实现 oau
知识点概括
环境介绍
- 使用 laradock 作为 laravel 的开发环境
PHP 7.2、MySQL 5.7
- Node 环境
node 9.8、npm 5.6
项目架构
- Server 项目用于搭建 验证授权服务器
- Client 项目用于 第三方应用
设计逻辑
实现类似与微信授权登陆的逻辑。
挡在微信中进入其它网页时,会出现类似授权的页面,当点击授权后即可获取用户的信息。
image.png
Server 项目搭建
- 首先使用命令创建 Server 项目
composer create-project laravel/laravel --prefer-dist server
- 配置数据库
# .env
...
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=server
DB_USERNAME=root
DB_PASSWORD=root
...
laradock 中 host 必须填写 mysql,自动转发到 mysql 容器中
- 安装
laravel/passport
composer require laravel/passport
laravel 5.5 以后有自动发现机制,不需要配置 provider,低于该版本请按照手册自行配置。
- 执行数据库迁移,并添加 auth 脚手架。
$ php artisan migrate
$ php artisan make:auth
当执行完 make:auth
后首页上就会出现注册与登录。
- 生成 passport key 以及一些 password keys
php artisan passport:install
image.png
- 配置 config 文件
将 api 的driver 更换为 passport
# config/auth.config
...
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
...
这一步是实现 API Auth 授权中间件默认使用的驱动
- User 使用 Password 提供的 Trait
# App\User
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens;
...
}
- 配置 Passport 相关路由信息
# App\Providers\AuthServiceProvider
...
use Laravel\Passport\Passport;
class AuthServiceProvider extends ServiceProvider
{
...
public function boot()
{
$this->registerPolicies();
// Passport 路由
Passport::routes();
// Passport Token 过期时间
Passport::tokensExpireIn(Carbon::now()->addDay(15));
// Passport Refresh Token 过期时间
Passport::refreshTokensExpireIn(Carbon::now()->addDay(30));
}
}
- 生成前端脚手架,默认提供了 vue 相关模板,需要使用到 node
php artisan vendor:publish --tag=passport-components
image.png
- 使用 npm 或 cnpm 命令安装 package.json 的相关依赖
composer.json 与 package.json 类似,npm 与 composer 类似。使用 npm 必须安装 node 环境。npm 与 composer 类似,境外资源拉取非常慢,所以推荐使用淘宝镜像。具体设置方法请 Google。
npm install
image.png
- 然后将 component 组件注册到 vue 的根实例中
# resources/assets/js/app.js
Vue.component(
'passport-clients',
require('./components/passport/Clients.vue')
);
Vue.component(
'passport-authorized-clients',
require('./components/passport/AuthorizedClients.vue')
);
Vue.component(
'passport-personal-access-tokens',
require('./components/passport/PersonalAccessTokens.vue')
);
image.png
- 编译文件,生成 app.js 和 app.css
npm run dev
image.png
有一些同学可能会存在相关问题,比如笔者就遇到一个bug。
Module build failed: ReferenceError: Unknown plugin "transform-runtime"
,当遇到这个bug时第一时间google了一下,然后各种无法解决,仔细一看,原来是项目的上一级目录中存在一个.babelrc
文件,该文件 上一个 vue 项目的残余(没删除干净),然后删除之后就可以了。
这里笔者要说明的是:遇到问题不要紧张,首先看一下报错的信息,如果是 依赖没安装成功就删除 node_modules,重新安装下。如果是存在其它 bug,首先看看是不是本项目的,如果不是就删除它,如果是的话那么就 google 一下,查找一下解决方式,或者你可以留言。
- 这时,你就需要可以在 blade 模板里面引入编译好的 css 和 js 就可以了。
# resources/view/passport.blade.php
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
<!-- Vue 默认绑定的根节点 -->
<div id="app" class="container">
<passport-clients></passport-clients>
<passport-authorized-clients></passport-authorized-clients>
<passport-personal-access-tokens></passport-personal-access-tokens>
</div>
<!-- 必须放在 根节点 之后,否则无法正常解析-->
<script src="{{ mix('js/app.js') }}"></script>
</body>
</html>
- 添加路由
# routes/web.php
Route::get('/passport', function () {
return view('passport');
});
- 访问路由
server.test/passport
image.png
页面渲染,但是报错了 401 错误,这说明必须登录之后才能访问该路由。那么进入首页登录一下即可,没有账号就注册一个。
image.png
-
成功,并且无报错信息
image.png -
创建一个 Client
image.png
- 使用 浏览器 测试一下
http://server.test/oauth/authorize?client_id=your_client_id&redirect_uri=your_redirect_uri&response_type=code&scope=*
image.png将 client_id 和 redirect_uri 替换成你自己的即可
- 响应数据
http://client.test/authorizations?code=def50200b4bd56c76cf885df8f4871b1325aa23571c07fe149086c4a3795c7b6e286d19aef3101330fcaa7e19a8bebaabf4a3cb4cdfa6208934a4d42db4e5f2eee1ef0a78ae6da976da9764c75d7561f43cd12d3a2aacc20b94cc12b71aa2b7464c44438524e8b73c256b655168ed6087da8a82c011c1f86deb3a72cf30a4eba955579efce5cf007993c13ad1783beb43bb30980f5ac54b0a559148df3182839ee6522c0175eb24ce917f36a2b1bb70b4278dc29640d8251a83a9e8a58c559b8b7304e2edfaeb24c9f248f1eb0187ecff76ecb8ebdbd57a1da91ce4c84142946065cbdb5187e4f92f012ce49497f6fd471c2a9a6538f89a8194dda8b976f42377fa1b429237b7bf2606ab64fe459532fba35f61fb8262efc8b4931edcaaf0ff6ec87dba9894916a90ada15c9fd8f44a7520996e44bfa38fd8ae2c719cb098e673887eddbb2a01b5af9f7c062ffb991536cbdeff275a3b7a2556c595998eec98dda063759aa3d
-
通过 code 获取 access_token
image.png
把 client_id 和 client_secret 更换为你自己的
- 响应数据解读
token_type: Bearer 是 Oauth 2.0 的一种认证模式,一般均为此。
expires_in: 过期时间
access_token: 通讯密钥
refersh_token:刷新Token,是在 access_token 过期后,可以用此更换新的 access_token
还记得我们在 AuthProvider中设置的过期时间么?token 过期时间比 refresh_token 过期时间要短,我们设置的是 15天 和 30 天。
- 这时就可以拿着 access_token 去读取用户信息了
首先,定义一个 API 路由
# routes/api.php
Route::middleware('auth:api')->get('/user', function (Request $request) {
$user = \Auth::guard('api')->user();
return response()->json($user);
});
比如,在 API 路由中去读取用户信息,使用 Postman 测试一下。
image.png image.png
- 恭喜,基本完成了。
当然,笔者做的实验是利用 client 去实现 postman 的功能,但是发现 postman 更好用。client 端的代码其实就是做了一层转发的功能,让服务器保存 client_secret 更加安全。但基于实验,你完全可以使用 postman。
这里笔者只是基本完成了 laravel-passport 的授权模式, 如果还要更深的研究,你可以留言,我可以进行更加具体的教程解读。
这里笔者将代码放在 github上,如果你搭不起环境,可以直接拿来做实验 laravel-passport-test
Client 端代码