Laravel护照,根据用户的角色添加范围



我目前正在构建一个SPA类型的应用程序原型。第一步是使用Laravel Passport实现API并保护它。为此,我从这个现有的结构中汲取灵感:Laravel SPA。问题是,没有一个 API URL 受到保护,这意味着,作为用户,我可以从 API 请求所有信息。

所以我决定从头开始,提高安全性。我正在使用一个角色和权限包,即:拉拉维尔权限。

这是我第一次实现和 API,我被 Laravel 护照的范围概念困住了,因为它们可以直接添加到 API 请求中,而无需根据用户角色进行检查。

我找到了一个在StackOverflow上给出解决方案的人,可以在这里找到:基于角色的API URL保护。

所以这是我的实现:

// AuthServiceProvider
public function boot()
{
$this->registerPolicies();
// We define all the scopes for the tokens
Passport::tokensCan([
'manage-continents' => 'Manage continents scope',
'read-only-continents' => 'Read only continents scope',
]);
Passport::routes();
}

然后,我正在使用Laravel资源控制器创建一个REST控制器。

// Rest Controller
namespace AppHttpControllersAPIGeoLocation;
use IlluminateHttpRequest;
use AppHttpControllersController;
use AppModelsGeoLocationContinent as Continent;
class ContinentController extends Controller
{
public function index()
{
// allow listing all continents only for token with manage continent scope
return Continent::all();
}
public function store(Request $request)
{
// allow storing a newly created continent in storage for token with manage continent scope
}

public function show($id)
{
// allow displaying the continent for token with both manage and read only scope
}
}

然后在 api.php 文件中,我将添加以下路由:

Route::get('/continents', 'APIGeoLocationContinentController@index')
->middleware(['auth:api', 'scopes:manage-continents']);
Route::post('/continents', 'APIGeoLocationContinentController@store')
->middleware(['auth:api', 'scopes:manage-continents']);
Route::get('/continents/{id}', 'APIGeoLocationContinentController@show')
->middleware(['auth:api', 'scopes:manage-continents, read-only-continents']);

然后,我将创建一个控制器来拦截请求,并根据用户角色添加范围。问题,我认为这种方法永远不会达到,我将在后面解释。

namespace AppHttpControllersAuth;
use AppHttpControllersController;
use IlluminateFoundationAuthAuthenticatesUsers;
use IlluminateHttpRequest;
use IlluminateSupportFacadesRoute;
class ApiLoginController extends Controller
{
use AuthenticatesUsers;
protected function authenticated(Request $request, $user)
{   
// Implement your user role retrieval logic
// for example retrieve from `roles` database table
$roles = $user->getRoleNames();
$request->request->add(['username' => $request->email]); 
// @TODO to avoid many requests, we should just deepdive into
// the collection returned by the role
// grant scopes based on the role that we get previously
if ($roles->contains('hyvefive_super_administrator')) 
{
// grant manage order scope for user with admin role
$request->request->add([
'scope' => 'manage-continents'
]);
} 
else 
{
// read-only order scope for other user role
$request->request->add([
'scope' => 'read-only-continents'
]);
}
// forward the request to the oauth token request endpoint
$tokenRequest = Request::create(
'/oauth/token',
'post'
);
return Route::dispatch($tokenRequest);
}
}

测试所有内容之前的最后一步是在 api .php 文件中添加该控制器的路由:

Route::post('login', 'AuthApiLoginController@login');

最后,为了进行测试,我只是使用来自身份验证默认Laravel包的HomeController,如下所示:

namespace AppHttpControllers;
use IlluminateHttpRequest;
use GuzzleHttpClient;
use Auth;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* @return IlluminateHttpResponse
*/
public function index(Request $request)
{
// from client application
$http = new Client();
$response = $http->post('http://hyvefivity.local/api/login', [
'form_params' => [
'grant_type'    => 'password',
'client_id'     =>  4,
'client_secret' => 'fsW4E5fcQC0TGeVHOrvr1qlZ8TEgrgpSRziVLCDS',
'username'      => 'myemail@gmail.com',
'password'      => 'my-secret-password',
'scope'         => 'manage-continents',
],
]);
// You'd typically save this payload in the session
$auth = json_decode((string) $response->getBody(), true);
var_dump($auth);
/*$response = $http->get('http://hyvefivity.local/api/continents', [
'headers' => [
'Authorization' => 'Bearer '.$auth->access_token,
]
]);
$continents = json_decode( (string) $response->getBody() );
*/
// return view('home');
}
}

问题是我觉得从未到达ApiLoginController,并且经过身份验证的方法也是如此。

如果我正在执行以下操作:

$http = new Client();
$response = $http->post('http://hyvefivity.local/oauth/token', [
'form_params' => [
'grant_type'    => 'password',
'client_id'     =>  4,
'client_secret' => 'fsW4E5fcQC0TGeVHOrvr1qlZ8TEgrgpSRziVLCDS',
'username'      => 'my-email@gmail.com',
'password'      => 'my-seret-password',
'scope'         => 'manage-continents',
],
]);

生成了一个令牌,但不使用我在 ApiLoginController 中添加的作用域。

我还想做的另一项改进是:我是否应该在登录期间进行该 API 调用,因为如果我在 HomeController 中执行此操作,问题是密码是散列的,这意味着在登录期间没有密码就不可能要求密码授予类型的令牌?

护照默认提供它,但它也无法正常工作

Passport::actingAs($user,['scope']);

public static function actingAs($user, $scopes = [], $guard = 'api')

最新更新