手摸手,教你使用 laravel-passport 实现 oauth 2.0 验证机制

知识点概括

  1. oauth 2.0 概念
  2. laravel passport 基本使用
  3. guzzlehttp 组件使用

环境介绍

  1. 使用 laradock 作为 laravel 的开发环境

PHP 7.2、MySQL 5.7

  1. Node 环境

node 9.8、npm 5.6

项目架构

  1. Server 项目用于搭建 验证授权服务器
  2. Client 项目用于 第三方应用
Oauth 2.0 验证流程示意图(引用于:阮一峰博客)

设计逻辑

实现类似与微信授权登陆的逻辑。
挡在微信中进入其它网页时,会出现类似授权的页面,当点击授权后即可获取用户的信息。


image.png

Server 项目搭建

  1. 首先使用命令创建 Server 项目
composer create-project laravel/laravel --prefer-dist server
  1. 配置数据库
# .env
...
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=server
DB_USERNAME=root
DB_PASSWORD=root
...

laradock 中 host 必须填写 mysql,自动转发到 mysql 容器中

  1. 安装laravel/passport
composer require laravel/passport

laravel 5.5 以后有自动发现机制,不需要配置 provider,低于该版本请按照手册自行配置。

  1. 执行数据库迁移,并添加 auth 脚手架。
$ php artisan migrate
$ php artisan make:auth

当执行完 make:auth 后首页上就会出现注册与登录。

image.png

  1. 生成 passport key 以及一些 password keys
php artisan passport:install
image.png
  1. 配置 config 文件
    将 api 的driver 更换为 passport
# config/auth.config
...
'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
        ],
    ],
...

这一步是实现 API Auth 授权中间件默认使用的驱动

  1. User 使用 Password 提供的 Trait
# App\User
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
  use HasApiTokens;
  ...
}
  1. 配置 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));
    }
}
  1. 生成前端脚手架,默认提供了 vue 相关模板,需要使用到 node
php artisan vendor:publish  --tag=passport-components
image.png
  1. 使用 npm 或 cnpm 命令安装 package.json 的相关依赖
    composer.json 与 package.json 类似,npm 与 composer 类似。使用 npm 必须安装 node 环境。npm 与 composer 类似,境外资源拉取非常慢,所以推荐使用淘宝镜像。具体设置方法请 Google。
npm install 
image.png
  1. 然后将 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
  1. 编译文件,生成 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 一下,查找一下解决方式,或者你可以留言。

  1. 这时,你就需要可以在 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>
  1. 添加路由
# routes/web.php
Route::get('/passport', function () {
    return view('passport');
});
  1. 访问路由
server.test/passport
image.png

页面渲染,但是报错了 401 错误,这说明必须登录之后才能访问该路由。那么进入首页登录一下即可,没有账号就注册一个。


image.png
  1. 成功,并且无报错信息


    image.png
  2. 创建一个 Client


    image.png
image.png
  1. 使用 浏览器 测试一下
http://server.test/oauth/authorize?client_id=your_client_id&redirect_uri=your_redirect_uri&response_type=code&scope=*

将 client_id 和 redirect_uri 替换成你自己的即可

image.png
  1. 响应数据
http://client.test/authorizations?code=def50200b4bd56c76cf885df8f4871b1325aa23571c07fe149086c4a3795c7b6e286d19aef3101330fcaa7e19a8bebaabf4a3cb4cdfa6208934a4d42db4e5f2eee1ef0a78ae6da976da9764c75d7561f43cd12d3a2aacc20b94cc12b71aa2b7464c44438524e8b73c256b655168ed6087da8a82c011c1f86deb3a72cf30a4eba955579efce5cf007993c13ad1783beb43bb30980f5ac54b0a559148df3182839ee6522c0175eb24ce917f36a2b1bb70b4278dc29640d8251a83a9e8a58c559b8b7304e2edfaeb24c9f248f1eb0187ecff76ecb8ebdbd57a1da91ce4c84142946065cbdb5187e4f92f012ce49497f6fd471c2a9a6538f89a8194dda8b976f42377fa1b429237b7bf2606ab64fe459532fba35f61fb8262efc8b4931edcaaf0ff6ec87dba9894916a90ada15c9fd8f44a7520996e44bfa38fd8ae2c719cb098e673887eddbb2a01b5af9f7c062ffb991536cbdeff275a3b7a2556c595998eec98dda063759aa3d
  1. 通过 code 获取 access_token


    image.png

把 client_id 和 client_secret 更换为你自己的

  1. 响应数据解读
    token_type: Bearer 是 Oauth 2.0 的一种认证模式,一般均为此。
    expires_in: 过期时间
    access_token: 通讯密钥
    refersh_token:刷新Token,是在 access_token 过期后,可以用此更换新的 access_token

还记得我们在 AuthProvider中设置的过期时间么?token 过期时间比 refresh_token 过期时间要短,我们设置的是 15天 和 30 天。

  1. 这时就可以拿着 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
  1. 恭喜,基本完成了。
    当然,笔者做的实验是利用 client 去实现 postman 的功能,但是发现 postman 更好用。client 端的代码其实就是做了一层转发的功能,让服务器保存 client_secret 更加安全。但基于实验,你完全可以使用 postman。

这里笔者只是基本完成了 laravel-passport 的授权模式, 如果还要更深的研究,你可以留言,我可以进行更加具体的教程解读。

这里笔者将代码放在 github上,如果你搭不起环境,可以直接拿来做实验 laravel-passport-test

Client 端代码
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 原文链接 必备品 文档:Documentation API:API Reference 视频:Laracasts ...
    layjoy阅读 8,603评论 0 121
  • 1.在应用目录下执行 php artisan make:auth 和 php artisan migrate命令,...
    Stargazes阅读 698评论 0 0
  • 安装# 安装 Passport# 1.在你的 Shell 中执行以下命令 composerrequirelarav...
    绿豆包包阅读 765评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 前言 也可以关注我的个人博客  这里摘录下laravel5.5教程的认证文档,做个总结,方便今后查阅。 安装pas...
    小峰书阅读 2,094评论 0 1