利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法

利用Laravel 搭建oauth2 API接口

要求

laravel 5.4以上php

安装

$ composer require laravel/passportlaravel

在配置文件 config/app.php 的providers 数组中注册 Passport 服务提供者:sql

LaravelPassportPassportServiceProvider::class,数据库

迁移数据库 执行完后会生成oauth须要的表json

$ php artisan migrateapi

这一步注意,执行的时候可能会报错数组

Syntax error or access violation: 1071 Specified key was too long; max key length is 767 byte微信

这是因为 Laravel5.4默认使用utf8mb4 编码
utf8 最大长度字符是3字节 utf8mb4是4字节app

解决方法就是composer

  1. 数据库改用utf8mb4

  2. AppServiceProvider.php里面加上Schema::defaultStringLength(191);

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //

        Schema::defaultStringLength(191);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

另外Mysql 5.5.3以后才支持utf8mb4也须要注意下

接下来执行

$ php artisan passport:install

会生成两个客户端密钥

Client ID: 1
Client Secret: AwDMcCs65rXkzF80wPaINx5fkoXEfa8lcuuPEvQK
Password grant client created successfully.
Client ID: 2
Client Secret: KLlLijWk3hX2Ntfzo2iFPgwT4GyITpBjEuDozp5H

配置

这里能够配置的只有access token的生命周期默认是永久的
在AuthServiceProvider中配置

use Carbon\Carbon;
use Laravel\Passport\Passport;

/**
 * 注册全部认证/受权服务.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    Passport::routes();
    Passport::tokensExpireIn(Carbon::now()->addDays(15));
    Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));
}

修改auth.php
'guards'['driver'] => 'passport'

发放access_token

颁发

应用场景 个人用户,在别的网站想用个人帐号直接登陆,参考微信登陆。那么第三方网站就要对接过来,用户选择第三方登陆,跳转到个人页面,询问用户是否容许,用户容许之后我会带一个code回去,第三方网站用这个code请求access_token

流程是

请求令牌

'client_id' => 'client-id',
    'redirect_uri' => 'http://example.com/callback',
    'response_type' => 'code',
    'scope' => '',

用户容许之后拿到code换token

$response = $http->post('http://your-app.com/oauth/token', [
        'form_params' => [
            'grant_type' => 'authorization_code',
            'client_id' => 'client-id',
            'client_secret' => 'client-secret',
            'redirect_uri' => 'http://example.com/callback',
            'code' => $request->code,
        ],
    ]);

token若是过时了,能够刷新

$response = $http->post('http://your-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'refresh_token',
        'refresh_token' => 'the-refresh-token',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'scope' => '',
    ],
]);

帐号密码

这个主要是用于APP(我本身的),用户经过app输入帐号和密码,我用帐号密码校验正确了就发送access_token

$response = $http->post('http://your-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'password',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'username' => 'taylor@laravel.com',
        'password' => 'my-password',
        'scope' => '',
    ],
]);

隐式

这种跟第一种差很少,就是省去了code 直接发放,主要用于

JavaScript 或移动应用中客户端登陆认证信息不能保存时

客户端证书

这种主要用于机器之间的通讯
直接用appid 和 appsecret 换令牌

$response = $guzzle->post('http://your-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'client_credentials',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'scope' => 'your-scope',
    ],
]);

私人访问令牌

这个用于在程序里面调用API的时候
好比

$user = App\User::find(1);

// 建立一个不带域的令牌...
$token = $user->createToken('Token Name')->accessToken;

// 建立一个带域的令牌...
$token = $user->createToken('My Token', ['place-orders'])->accessToken;

在调用api以前须要建立client
建立命令是
$ php artisan passport:client

密码和私人的不一样其余都同样

$ php artisan passport:client --password
$ php artisan passport:client --personal

建立好后得到client-id和client-secret

建立路由

5.4之后目录结构发生变化,路由统一写在routes文件夹下。
API的路由都写在api.php

肯定好路由就能够请求接口了

GET 方式
    /api/user
    'headers' => [
        'Accept' => 'application/json',
        'Authorization' => 'Bearer '.$accessToken,
    ],

写到这里遇到一个问题

就是不管怎样请求 获取到的token 用来访问接口的时候 老是返回
Unauthenticated

GOOGLE了下发现好多人也遇到这个问题,听说是token过时时间的问题

在AuthServiceProvider boot里面加上

Passport::tokensExpireIn(Carbon::now()->addDays(15));
Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));

这样应该会解决,然而并无,这里等之后一时间再研究下(已解决 见下文)

这个问题有了必定进展

目前经过用户受权颁发令牌的方式经过了

前提是用户必须登陆,以前返回Unauthenticated 应该是由于用户未登陆

在应用站跳转到受权站的时候,此时用户需登陆状态,受权之后拿到code再来换access_token 这个方式OK的,能够正常获取登陆用户的信息

帐号密码获取令牌的方式也同样能够经过

站点以前经过 id 和 secret的方式换token,而后拿token请求接口这种方式目前还不行

坑爹啊,官方文档没写全

经过 client_credentials 方式获取token,请求接口的时候,路由不能用auth或者scope等中间件去验证,由于他们会首先验证有没有登陆。

咱们须要在app\Http\Kernel.php 的 $routeMiddleware 里面定义一个客户端API的中间件

'client_credentials' => \Laravel\Passport\Http\Middleware\CheckClientCredentials::class,

而后在路由里面
Route::middleware('client_credentials')

或者

Route::middleware('client_credentials:做用域名称')

这样就能够实现不登陆直接调用api了

参考文档

https://laravel.com/docs/5.4/...

相关文章
相关标签/搜索