Laravel的5.3护照和api路线

And*_*rei 15 php laravel-5.3

我正在使用Laravel Framework版本5.3.9,通过composer(除了"laravel/passport": "^1.0")没有添加任何新内容.

我做了文档中建议的所有事情.表已创建,路由已启动,一切正常.但是我需要API的护照.

我的路线看起来像这样:

+--------+----------+-----------------------------------------+----------------------+----------------------------------------------------------------------------+------------+
| Domain | Method   | URI                                     | Name                 | Action                                                                     | Middleware |
+--------+----------+-----------------------------------------+----------------------+----------------------------------------------------------------------------+------------+
|        | GET|HEAD | /                                       |                      | Closure                                                                    | web        |
|        | GET|HEAD | api/v1/users/register                   | api::users::register | App\Http\Controllers\Api\V1\SocialController@register                      | api,auth   |
|        | POST     | oauth/authorize                         |                      | \Laravel\Passport\Http\Controllers\ApproveAuthorizationController@approve  | web,auth   |
|        | GET|HEAD | oauth/authorize                         |                      | \Laravel\Passport\Http\Controllers\AuthorizationController@authorize       | web,auth   |
|        | DELETE   | oauth/authorize                         |                      | \Laravel\Passport\Http\Controllers\DenyAuthorizationController@deny        | web,auth   |
|        | GET|HEAD | oauth/clients                           |                      | \Laravel\Passport\Http\Controllers\ClientController@forUser                | web,auth   |
|        | POST     | oauth/clients                           |                      | \Laravel\Passport\Http\Controllers\ClientController@store                  | web,auth   |
|        | PUT      | oauth/clients/{client_id}               |                      | \Laravel\Passport\Http\Controllers\ClientController@update                 | web,auth   |
|        | DELETE   | oauth/clients/{client_id}               |                      | \Laravel\Passport\Http\Controllers\ClientController@destroy                | web,auth   |
|        | GET|HEAD | oauth/personal-access-tokens            |                      | \Laravel\Passport\Http\Controllers\PersonalAccessTokenController@forUser   | web,auth   |
|        | POST     | oauth/personal-access-tokens            |                      | \Laravel\Passport\Http\Controllers\PersonalAccessTokenController@store     | web,auth   |
|        | DELETE   | oauth/personal-access-tokens/{token_id} |                      | \Laravel\Passport\Http\Controllers\PersonalAccessTokenController@destroy   | web,auth   |
|        | GET|HEAD | oauth/scopes                            |                      | \Laravel\Passport\Http\Controllers\ScopeController@all                     | web,auth   |
|        | POST     | oauth/token                             |                      | \Laravel\Passport\Http\Controllers\AccessTokenController@issueToken        |            |
|        | POST     | oauth/token/refresh                     |                      | \Laravel\Passport\Http\Controllers\TransientTokenController@refresh        | web,auth   |
|        | GET|HEAD | oauth/tokens                            |                      | \Laravel\Passport\Http\Controllers\AuthorizedAccessTokenController@forUser | web,auth   |
|        | DELETE   | oauth/tokens/{token_id}                 |                      | \Laravel\Passport\Http\Controllers\AuthorizedAccessTokenController@destroy | web,auth   |
+--------+----------+-----------------------------------------+----------------------+----------------------------------------------------------------------------+------------+
Run Code Online (Sandbox Code Playgroud)

所有的web路线都在那里,没有api相关的路线,因为Passport没有提供开箱即用的任何东西.

API本身旨在供受信任的客户端使用,它是为需要登录的移动应用程序而设计的,然而,所述登录将绕过几个步骤.

一旦用户访问该/register路线,注册过程本身就非常简单:访问用户的Facebook帐户,抓住几个字段 - 电子邮件,脸谱ID,命名个人资料图片,从那时起,用户被视为已注册.但用户不会登录facebook(这是一个非常重要的方面).消费者应用程序将被发出一个令牌并使用该令牌访问api的各个端点(需要使用令牌).

所以归结为这个.我需要向访问API的消费者应用程序发出访问令牌.API本身只有一个客户端,即移动应用程序本身.使用该应用程序的用户不被视为API的客户端,而是移动应用程序本身的客户端.

到目前为止,在实现API相关的东西时,Passport是一个令人头痛的问题,或者我无法弄清楚如何让它正常工作.

我在oauth_clients表中创建了一个看起来像这样的测试客户端:

在此输入图像描述

我正在使用Postman访问api/v1/users/register具有以下auth中间件的路由JSON application/json

{
    "grant_type" : "authorization_code",
    "client_id" : 5,
    "client_secet": "y5dvPIOxQJOjYn7w2zzg4c6TRrphsrNFWbG4gAUL"
}
Run Code Online (Sandbox Code Playgroud)

这当然会导致一个

{"error":"Unauthenticated."}
Run Code Online (Sandbox Code Playgroud)

这很有道理.出于纯粹的好奇心,我改变了这/register条路线:

Route::group([
    'middleware' => [
    ],
], function ()
{
    Route::group([
        'prefix' => 'users',
        'as'     => 'users::',
    ], function ()
    {
//        Route::get('/register', ['as'   => 'register', 'uses' => 'Api\V1\SocialController@register',]);
        Route::post('/register', ['as'   => 'register', 'uses' => '\Laravel\Passport\Http\Controllers\AccessTokenController@issueToken',]);
    });

});
Run Code Online (Sandbox Code Playgroud)

跟json以前一样.结果导致了{"error":"invalid_client","message":"Client authentication failed"}.

我已经找到了,我认为,处理功能validateClient部分vendor/league的oauth2服务器/ src目录/格兰特/ AbstractGrant`.

该$client为空.现在这可能与Passport有关,也可能没有关系,因为它上面的文档相当缺乏,并想通过一个包的怪物来挖掘错误,这可能主要是由于我没有做正确的事情,这并没有让我受伤作为一个好主意,我没有选择.说实话,我甚至不知道问题是什么.

真的,在这一点上任何指向正确方向的东西都非常受欢迎.

问题的部分是

Shu*_*med 21

Laravel 5.3护照的问题在于,与之前由lucadegasperi提供的Laravel库的OAuth 2.0服务器不同,它没有直接创建客户端的API.因此,现在客户端只能通过前端进行.仅供参考我们希望仅为我们的移动应用程序使用laravel护照,因此在创建和注册用户时,我们只有EMAIL和密码,在某些情况下只有Facebook用户ID才能登录.因此,以下方法对我们的情况非常有效,并且可能因您的情况而有所不同,但可能会帮助您从长远来看使用laravel护照.

注意:在遵循以下内容之前,假设您已在应用程序中启用了密码授予.

所以我们为laravel 5.3项目解决它的方式如下:

  1. 在oauth_clients中将id字段转换为普通字段,即将其作为主键删除,并将数据类型设置为varchar,以便我们可以将电子邮件地址存储为client_ids,因为它们对于您的系统也是唯一的.在Facebook登录的情况下,我们将Facebook用户ID存储在此列中,这对于我们的每个客户来说也是唯一的.对于其他表,例如:oauth_access_tokens,oauth_auth_codes和oauth_personal_access_clients将client_id更改为VARCHAR(255),以便它可以存储电子邮件地址或Facebook用户ID.

  2. 现在转到模型并为oauth_clients表创建模型,以便您可以在创建用户时以编程方式从代码创建客户端.

    <?php
    namespace App;
    
    
    use Illuminate\Database\Eloquent\Model;
    
    class OauthClient extends Model
    {
        protected $table = 'oauth_clients';
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 然后在api.php路由文件中添加以下路由:

    Route::post('/register-user', function (Request $request) {
    
        $name     = $request->input('name');
        $email    = $request->input('email'),
        $password = $request->input('password'),    
    
        // save new user
        $user = \App\User::create([
          'name'     => $name,
          'email'    => $email,
          'password' => bcrypt($password),
        ]);
    
    
        // create oauth client
        $oauth_client = \App\OauthClient::create([
            'user_id'                => $user->id,
            'id'                     => $email,
            'name'                   => $name,
            'secret'                 => base64_encode(hash_hmac('sha256',$password, 'secret', true)),
            'password_client'        => 1,
            'personal_access_client' => 0,
            'redirect'               => '',
            'revoked'                => 0,
        ]);
    
    
        return [
            'message' => 'user successfully created.'
        ];
    });
    
    Run Code Online (Sandbox Code Playgroud)

在上面的代码片段中,您必须注意,要生成oauth_client秘密,您必须使用一些强大的加密公式,您觉得将其与您的应用程序一起使用是很舒服的.此外,使用相同的技术在您的移动应用程序上为相应的客户端/用户生成密钥.

  1. 现在,您可以使用laravel passport提供的标准POST API,使用以下参数使用"oauth/token"通过密码授权请求访问令牌:

    grant_type : 'password'
    client_id  : '<email with which the user is registered>'
    client_secret : '<generate the client secret from the mobile app>'
    username : '<email with which the user is registered>'
    password : '<password entered by the user>'
    scope : '<leave empty as default>'
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果一切正确,上面会给你一个回应,类似于:

    {
      "token_type": "Bearer",
      "expires_in": 3155673600,
      "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjMwZmM0MDk1NWY5YjUwNDViOTUzNDlmZjc2M2ExNDUxOTAxZjc5YTA5YjE4OWM1MjEzOTJlZmNiMDgwOWQzMzQwM2ExZWI4ZmMyODQ1MTE3In0.eyJhdWQiOiJzaHVqYWhtQGdtYWlsLmNvbSIsImp0aSI6IjMwZmM0MDk1NWY5YjUwNDViOTUzNDlmZjc2M2ExNDUxOTAxZjc5YTA5YjE4OWM1MjEzOTJlZmNiMDgwOWQzMzQwM2ExZWI4ZmMyODQ1MTE3IiwiaWF0IjoxNDc4MTQ1NjMyLCJuYmYiOjE0NzgxNDU2MzIsImV4cCI6NDYzMzgxOTIzMiwic3ViIjoiMSIsInNjb3BlcyI6W119.dj3g9b2AdPCK-im5uab-01SP71S7AR96R0FQTKKoaZV7M5ID1pSXDlmZw96o5Bd_Xsy0nUqFsPNRQsLvYaOuHZsP8v9mOVirBXLIBvPcBc6lDRdNXvRidNqeh4JHhJu9a5VzNlJPm3joBYSco4wYzNHs2BPSxXuuD3o63nKRHhuUHB-HwjVxj2GDwzEYXdZmf2ZXOGRJ99DlWGDvWx8xQgMQtd1E9Xk_Rs6Iu8tycjBpKBaC24AKxMI6T8DpelnFmUbMcz-pRsgCWCF_hxv6FpXav3jr1CLhhT58_udBvXjQAXEbtHeB7W_oaMcaqezHdAeOWDcnqREZHsnXHtKt0JpymcTWBkS2cg7sJzy6P9mOGgQ8B4gb8wt44_kHTeWnokk4yPFRZojkHLVZb8YL6hZxLlzgV1jCHUxXoHNe1VKlHArdlV8LAts9pqARZkyBRfwQ8oiTL-2m16FQ_qGg-9vI0Suv7d6_W126afI3LxqDBi8AyqpQzZX1FWmuJLV0QiNM0nzTyokzz7w1ilJP2PxIeUzMRlVaJyA395zq2HjbFEenCkd7bAmTGrgEkyWM6XEq1P7qIC_Ne_pLNAV6DLXUpg9bUWEHhHPXIDYKHS-c3N9fPDt8UVvGI8n0rPMieTN92NsYZ_6OqLNpcm6TrhMNZ9eg5EC0IPySrrv62jE",
      "refresh_token": "BbwRuDnVfm7tRQk7qSYByFbQKK+shYPDinYA9+q5c/ovIE1xETyWitvq6PU8AHnI5FWb06Nl2BVoBwCHCUmFaeRXQQgYY/i5vIDEQ/TJYFLVPRHDc7CKILF0kMakWKDk7wJdl5J6k5mN38th4pAAZOubiRoZ+2npLC7OSZd5Mq8LCBayzqtyy/QA5MY9ywCgb1PErzrGQhzB3mNhKj7U51ZnYT3nS5nCH7iJkCjaKvd/Hwsx2M6pXnpY45xlDVeTOjZxxaOF/e0+VT2FP2+TZMDRfrSMLBEkpbyX0M/VxunriRJPXTUvl3PW0sVOEa3J7+fbce0XWAKz7PNs3+hcdzD2Av2VHYF7/bJwcDCO77ky0G4JlHjqC0HnnGP2UWI5qR+tCSBga7+M1P3ESjcTCV6G6H+7f8SOSv9FECcJ8J5WUrU+EHrZ95bDtPc9scE4P3OEQaYchlC9GHk2ZoGo5oMJI6YACuRfbGQJNBjdjxvLIrAMrB6DNGDMbH6UZodkpZgQjGVuoCWgFEfLqegHbp34CjwL5ZFJGohV+E87KxedXE6aEseywyjmGLGZwAekjsjNwuxqD2QMb05sg9VkiUPMsvn45K9iCLS5clEKOTwkd+JuWw2IU80pA24aXN64RvOJX5VKMN6CPluJVLdjHeFL55SB7nlDjp15WhoMU1A="
    }
    
    Run Code Online (Sandbox Code Playgroud)

它只是一个临时解决方案,直到laravel为只有移动设备作为创建oAuth客户端和用户的唯一可能接口的应用程序支持外部API.

希望它能帮到你!干杯.


And*_* F. 10

因为标记的答案被认为是正确的,所以我觉得有必要注意一些我认为会同意的关键点:

  1. 你几乎从来没有想要把你的路由目录中的那种服务器进程逻辑.特别是在创建一个旨在将其投入生产的API时.这是一条肮脏的路线,并不完全安全. 除非是在您的路径目录中可以安全处理的事情.比如,在较小的范围内,用于向工作人员发送关于作为示例发布的新信件/博客/备忘录的通知(SMS,电子邮件,推送,松弛)的基本逻辑.

  2. 在尝试"hackishly"完成之前可能已完成多次的任务之前,始终尝试利用并尽可能多地利用框架的功能.

  3. 确保您正在对已经完成的事情进行适当的研究.这样,它可以更容易地简单地引用一个视频或教程,显示如何正确地做某人正在尝试做的事情.

话虽如此,一个很好的起点是观看以下视频,该视频完美地描述了如何正确设置您要设置的内容的基础知识:

https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/13

在许多方面,视频教程从头到尾都做得非常好,彻底.请务必仔细查看OAuth2.0的不同Grant_Types,以便根据应用程序使用api的位置更好地了解您/您的应用程序需要的特定类型:

https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2

此外,在创建或登录用户时,请务必使用laravel的开箱即用功能进行登录和注册.在控制台中执行以下操作时,将为您构建控制器:

php artisan make:auth
Run Code Online (Sandbox Code Playgroud)

除此之外,如果护照是一些神秘的东西,你可以随时拉入laravel/socialite包(https://github.com/laravel/socialite).它将允许您"登录(社交网络在这里)".只要这也是你想要去的路线.

结束注意:我在你的问题中看到的最突出的部分是一个人如何注册但不会登录facebook.相反,将有一个访问令牌来命中各种API端点.因此,如果我得到你说得对的话,你的目的是在返回数据时使用来自facebook的用户数据,用户被认为已登录并将获得访问令牌.所以:

  1. 使用社交名流向Facebook发送"登录facebook"请求.这将获取用户的数据并利用Facebook的一些身份验证过程.

  2. 当返回包含正文中的用户数据的请求时,通过检查运行它以确保存在数据(简单的if语句应该没问题).由于Facebook已经验证了该用户和发送的凭据,因此您应该很高兴.

  3. 您可以在登录控制器中启动内部代理(这是更干净,更安全的方式),或者您可以发出JWT(在上面的答案中发布的视频的最后5分钟内介绍了JWT).

    下面是一些示例代码,可帮助您入门.

    应用程序\ HTTP\\控制器验证\ LoginController.php

    class LoginController extends Controller
    {
    
        // ...
    
        protected function authenticateClient(Request $request) {
    
            $credentials = $this->credentials($request);
    
            $data = $request->all();
    
            $user = User::where('email', $credentials['email'])->first();
    
            $request->request->add([
                'grant_type'    => $data['grant_type'],
                'client_id'     => $data['client_id'],
                'client_secret' => $data['client_secret'],
                'username'      => $credentials['email'],
                'password'      => $credentials['password'],
                'scope'         => null,
            ]);
    
            $proxy = Request::create(
                'oauth/token',
                'POST'
            );
    
            return Route::dispatch($proxy);
        }
    
        protected function authenticated(Request $request, $user) {
    
            return $this->authenticateClient($request);
        }
    
        protected function sendLoginResponse(Request $request)
        {
            $request->session()->regenerate();
    
            $this->clearLoginAttempts($request);
    
            return $this->authenticated($request, $this->guard()->user());
    
        }
    
        public function login(Request $request)
        {
    
            if ($this->guard('api')->attempt($credentials, $request->has('remember'))) {
    
                return $this->sendLoginResponse($request);
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

以上代码用于IN CASE,您的目标是使用密码授权类型通过护照验证客户端.但是,在开枪之前我会认真看一下教程视频.如果使用laravel 5.3护照,它将帮助你解决很多问题.