谢谢你,这个问题让我困惑了一段时间!我采用 Raymond Lagonda 的解决方案为 Laravel 5.6 进行了一些定制,使用内置的速率限制,使用单个thirdparty
客户端(或者如果需要,可以进行更多自定义),同时仍然为每个用户提供权限列表(范围)。
- 使用 Laravel Passport
password
授权并遵循 Oauth 流程
- 使您能够为不同的用户设置角色(范围)
- 不要公开/发布客户端 ID 或客户端密码,只有用户的用户名(电子邮件)和密码,几乎是密码授权,减去客户端/授权的东西
底部示例
路线/api.php
Route::group(['namespace' => 'ThirdParty', 'prefix' => 'thirdparty'], function () {
Route::post('login', 'ApiLoginController@login');
});
第三方/ApiLoginController.php
<?php
namespace App\Http\Controllers\ThirdParty;
use Hash;
use App\User;
use App\ThirdParty;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class ApiLoginController extends Controller
{
use AuthenticatesUsers;
/**
* Thirdparty login method to handle different
* clients logging in for different reasons,
* we assign each third party user scopes
* to assign to their token, so they
* can perform different API tasks
* with the same token.
*
* @param Request $request
* @return Illuminate\Http\Response
*/
protected function login(Request $request)
{
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
$user = $this->validateUserLogin($request);
$client = ThirdParty::where(['id' => config('thirdparties.client_id')])->first();
$request->request->add([
'scope' => $user->scopes,
'grant_type' => 'password',
'client_id' => $client->id,
'client_secret' => $client->secret
]);
return Route::dispatch(
Request::create('/oauth/token', 'post')
);
}
/**
* Validate the users login, checking
* their username/password
*
* @param Request $request
* @return User
*/
public function validateUserLogin($request)
{
$this->incrementLoginAttempts($request);
$username = $request->username;
$password = $request->password;
$user = User::where(['email' => $username])->first();
abort_unless($user, 401, 'Incorrect email/password.');
$user->setVisible(['password']);
abort_unless(Hash::check($password, $user->password), 401, 'Incorrect email/password.');
return $user;
}
}
配置/第三方.php
<?php
return [
'client_id' => env('THIRDPARTY_CLIENT_ID', null),
];
第三方.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class ThirdParty extends Model
{
protected $table = 'oauth_clients';
}
.env
## THIRDPARTIES
THIRDPARTY_CLIENT_ID=3
php artisan make:migration add_scope_to_users_table --table=users
// up
Schema::table('users', function (Blueprint $table) {
$table->text('scopes')->nullable()->after('api_access');
});
// down
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('scopes');
});
(注意:api_access
是一个标志,它决定用户是否可以登录到应用程序的网站/前端部分,查看仪表板/记录等),
路线/api.php
Route::group(['middleware' => ['auth.client:YOUR_SCOPE_HERE', 'throttle:60,1']], function () {
...routes...
});
MySQL - 用户范围
INSERT INTO `users` (`id`, `created_at`, `updated_at`, `name`, `email`, `password`, `remember_token`, `api_access`, `scopes`)
VALUES
(5, '2019-03-19 19:27:08', '2019-03-19 19:27:08', '', 'hello@email.tld', 'YOUR_HASHED_PASSWORD', NULL, 1, 'YOUR_SCOPE_HERE ANOTHER_SCOPE_HERE');
MySQL - ThirdParty
Oauth 客户端
INSERT INTO `oauth_clients` (`id`, `user_id`, `name`, `secret`, `redirect`, `personal_access_client`, `password_client`, `revoked`, `created_at`, `updated_at`)
VALUES
(3, NULL, 'Thirdparty Password Grant Client', 'YOUR_SECRET', 'http://localhost', 0, 1, 0, '2019-03-19 19:12:37', '2019-03-19 19:12:37');
cURL - 登录/请求令牌
curl -X POST \
http://site.localhost/api/v1/thirdparty/login \
-H 'Accept: application/json' \
-H 'Accept-Charset: application/json' \
-F username=hello@email.tld \
-F password=YOUR_UNHASHED_PASSWORD
{
"token_type": "Bearer",
"expires_in": 604800,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciO...",
"refresh_token": "def502008a75cd2cdd0dad086..."
}
像往常一样使用长寿命的 access_token/refresh_token!
访问禁止范围
{
"data": {
"errors": "Invalid scope(s) provided."
},
"meta": {
"code": 403,
"status": "FORBIDDEN"
}
}