我已经为Laravel 5.3设置了 Laravel Passport 包,正如官方文档(https://laravel.com/docs/5.3/passport#introduction)中所述。
我希望API由移动应用程序使用,因此我尝试实施密码授予令牌。我创建了一个密码授予客户端,以及令牌请求进程......
$response = $http->post('http://my-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => 'my@email.com',
'password' => 'my-password',
'scope' => '',
],
]);
...按预期工作,为我的一位用户返回访问令牌和刷新令牌。
但现在我想定义一些范围,以便限制用户的访问权限......再次按照文档,我在 AuthServiceProvider.php的 boot 方法中定义了它们喜欢:
Passport::tokensCan([
'admin' => 'Perform every action',
'user' => 'Perform only normal user actions',
]);
在这种情况下,如果"恶意"普通用户请求一个令牌(使用上面的POST呼叫)指定'scope' => 'admin'
,他或她会得到一个管理员'令牌......这不是我想要的。
因此,我想知道在这种情况下工作流程如何有效地限制对普通用户的访问,以及我在哪里必须实现 范围验证逻辑
提前致谢。
答案 0 :(得分:5)
解决此问题的一种方法是创建中间件
例如,如果您只希望拥有来自example.com的电子邮件的用户请求管理域,您可以执行以下操作
示例ScopeLogic.php
中间件:
if ($request->input('grant_type') === 'password') {
$scope = $request->input('scope');
$username = $request->input('username');
if ($scope === 'admin' && (strpos($username, '@example.com') === false)) {
return response()->json(['message' => "Not authorized to request admin scope"], 401);
}
}
return $next($request);
当然,您必须将此范围添加到Kernel.php中的$ routeMiddleware数组
protected $routeMiddleware = [
...
'check-scopes' => \App\Http\Middleware\ScopeLogic::class
]
在Passport::routes()
中包装AuthServiceProvider.php
以检查此中间件
\Route::group(['middleware' => 'check-scopes'], function() {
Passport::routes();
});
Passport还将检查是否通过了正确的用户名和护照组合,因此您不必担心中间件
答案 1 :(得分:0)
在我看来,我认为大多数人对OAuth和API感到困惑的是,范围与“客户”有关,而与“资源所有者”本身无关。如果需要,客户端应该能够使用管理范围与API进行通信,或者根本不使用范围。如果他们将admin-ish类型范围与用户上下文(密码授予,授权代码授权等)一起使用,那么就不会阻止他们在API中进行需要针对该用户的范围的调用。对我来说,唯一真正被归类为恶意的人就是设法窃取包含管理范围的访问令牌的人。这就是为什么允许API实现者指定授予客户端的范围的原因,以及如果它是使用密码授予等内容的第一方应用程序,那么您作为用户别无选择,只能信任它与您的数据。
我不知道怎么会这样做并在另一个人的移动应用程序中使用检索到的令牌但如果您尝试使用管理范围手动请求令牌,那么我真的没有看到任何错误(除了你设置为用户上下文给应用程序更多的控制权,所以它甚至可能适得其反??
如果您需要更多控制权,那么您需要通过API并为资源服务器中的每个用户创建类似应用程序级权限的内容。
答案 2 :(得分:0)
我忘记了我在哪里阅读它,在某个地方出现了一些Github问题,但是显然Laravel并没有内置这种能力,每个客户都一视同仁,立即可用。
一个用户提供了一个很好的解决方案,我在这里建立了一个解决方案:https://stackoverflow.com/a/55285483/1132557