当前位置: 首页 > 知识库问答 >
问题:

Laravel passport,根据用户角色添加作用域

满耀
2023-03-14

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

所以我决定从零开始,更加安全。我使用的是一个角色和权限包:Laravel permission。

这是我第一次实现和API,我一直坚持使用Laravel passport的作用域概念,因为它们可以直接添加到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();
}

然后,我创建一个REST控制器与Laravel资源控制器。

// Rest Controller

namespace App\Http\Controllers\API\GeoLocation;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

use App\Models\GeoLocation\Continent 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', 'API\GeoLocation\ContinentController@index')
    ->middleware(['auth:api', 'scopes:manage-continents']);

Route::post('/continents', 'API\GeoLocation\ContinentController@store')
    ->middleware(['auth:api', 'scopes:manage-continents']);

Route::get('/continents/{id}', 'API\GeoLocation\ContinentController@show')
    ->middleware(['auth:api', 'scopes:manage-continents, read-only-continents']);

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

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

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', 'Auth\ApiLoginController@login');

最后,为了测试,我只是使用来自Auth默认Laravel包的HomeController,如下所示:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use GuzzleHttp\Client;
use Auth;

class HomeController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */
    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中调用API,问题是密码是散列的,这意味着在登录时如果没有密码,就不可能请求密码授予类型的令牌?

共有1个答案

姜俊逸
2023-03-14

Passport将其作为默认值提供,但它也不能正常工作

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



public static function actingAs($user, $scopes = [], $guard = 'api')
 类似资料:
  • 登录帧 菜单框架

  • 我是新来的python和创建不和谐的机器人在一般情况下,我不能为我的生命弄清楚如何让我的机器人分配一个角色给用户的用户请求。 我在互联网上搜索了几个小时,找到了一些例子,但它们都产生了错误。 以下是我的命令代码: 以下是我得到的错误:

  • 使用spring webmvc和spring security web 3.2版,我希望根据用户角色(或用户是否经过身份验证)返回不同的视图,以便对于请求,角色匿名用户(或未经身份验证的用户)获得欢迎页面,角色用户用户获得主页。 我目前的做法是使用常规控制器: 然而,我并不喜欢它,因为我觉得这个重定向应该用SpringSecurity来完成(我错了吗?)。您知道使用Spring Security配

  • 我正试图在我的注册功能中为用户分配一个角色。 通过使用以下代码: 当我试图运行上面的代码时,我得到了以下错误。 E/AndroidRuntime:致命异常:AsyncTask#2进程:info,pid:967 java.lang.runtimeException:在Android.os.AsyncTask$3处执行doInBackground()时发生错误。done(AsyncTask.java:

  • 我正在制作一个机器人,有一个自动角色系统,使用反应 以下是我当前相关代码的简化版本: 我只想知道如何使用对象向用户添加角色 我尝试了

  • 我希望能够运行以开始的命令!suspend,提到一个用户,然后确定一个时间长度,并在指定的时间长度内向提到的用户添加一个名为“suspend”的角色。 我不知道该怎么做,因为我对JDA太不熟悉,无法让它工作。除了实际添加的名为“暂停”的角色之外,我的一切都正常。