Подтвердить что ты не робот

Паспортные области Laravel

Я немного запутался в части области laravel.

У меня есть модель пользователя и таблица.

Как я могу назначить пользователю роль пользователя, клиента и/или администратора.

У меня есть SPA с vue и laravel api backend. Я использую https://laravel.com/docs/5.3/passport#consuming-your-api-with-javascript

    Passport::tokensCan([
        'user' => 'User',
        'customer' => 'Customer',
        'admin' => 'Admin',
    ]);

Как я могу назначить, какая модель пользователя имеет область (ы)?

Или объекты не совпадают с ролями?

Как вы это реализуете?

Спасибо заранее!

4b9b3361

Ответ 1

Или объекты не совпадают с ролями?

Самое большое различие между ними - это контекст, к которому они относятся. Управление доступом на основе ролей (RBAC) управляет контролем доступа пользователя при непосредственном использовании веб-приложения , а область Oauth-2 управляет доступом к ресурсам API для внешний клиент от имени пользователя.

Как я могу назначить, какая модель пользователя имеет область (ы)?

В общем потоке Oauth пользователю (как владельцу ресурса) предлагается разрешить клиенту то, что он может и не может сделать от своего имени, это то, что вы назвали область. В успешной авторизации область, запрашиваемая клиентом, будет laravel/passport

Определите области действия как для роли администратора, так и для пользователя. Будьте конкретны, как вы можете, например: admin может управлять порядком, а пользователь только читать его.

// in AuthServiceProvider boot
Passport::tokensCan([
    'manage-order' => 'Manage order scope'
    'read-only-order' => 'Read only order scope'
]);

Подготовьте контроллер REST

// in controller
namespace App\Http\Controllers;

class OrderController extends Controller
{   
    public function index(Request $request)
    {
        // allow listing all order only for token with manage order scope
    }

    public function store(Request $request)
    {
        // allow storing a newly created order in storage for token with manage order scope
    }

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

Назначьте маршрут с помощью защиты api и области действия

// in api.php
Route::get('/api/orders', '[email protected]')
    ->middleware(['auth:api', 'scopes:manage-order']);
Route::post('/api/orders', '[email protected]')
    ->middleware(['auth:api', 'scopes:manage-order']);
Route::get('/api/orders/{id}', '[email protected]')
    ->middleware(['auth:api', 'scopes:manage-order, read-only-order']);

И при выдаче маркера сначала проверьте роль пользователя и предоставите область действия на основе этой роли. Чтобы достичь этого, нам нужен дополнительный контроллер, который использует свойство AuthenticatesUsers для предоставления конечной точки входа.

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
        $role = $user->checkRole();

        // grant scopes based on the role that we get previously
        if ($role == 'admin') {
            $request->request->add([
                'scope' => 'manage-order' // grant manage order scope for user with admin role
            ]);
        } else {
            $request->request->add([
                'scope' => 'read-only-order' // read-only order scope for other user role
            ]);
        }

        // forward the request to the oauth token request endpoint
        $tokenRequest = Request::create(
            '/oauth/token',
            'post'
        );
        return Route::dispatch($tokenRequest);
    }
}

Добавить маршрут для конечной точки входа api

//in api.php
Route::group('namespace' => 'Auth', function () {
    Route::post('login', '[email protected]');
});

Вместо того, чтобы делать POST для маршрута /oauth/token, POST в конечную точку входа api, которую мы предоставили перед

// from client application
$http = new GuzzleHttp\Client;

$response = $http->post('http://your-app.com/api/login', [
    'form_params' => [
        'grant_type' => 'password',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'username' => '[email protected]',
        'password' => 'my-password',
    ],
]);

return json_decode((string) $response->getBody(), true);

После успешной авторизации для клиентского приложения будет выпущено access_token и refresh_token на основе области, которую мы определяем ранее. Храните это где-нибудь и включайте токен в HTTP-заголовок всякий раз, когда отправляете запрос в API.

// from client application
$response = $client->request('GET', '/api/my/index', [
    'headers' => [
        'Accept' => 'application/json',
        'Authorization' => 'Bearer '.$accessToken,
    ],
]);

Теперь API должен возвращать

{"error":"unauthenticated"}

когда токен с привилегией используется для использования ограниченной конечной точки.

Ответ 2

Внедрите ответ Raymond Lagonda, и он работает очень хорошо, просто чтобы быть осторожным со следующим. Вам необходимо переопределить некоторые методы из атрибутов AuthenticatesUsers в ApiLoginController:

    /**
     * Send the response after the user was authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    protected function sendLoginResponse(Request $request)
    {
        // $request->session()->regenerate(); // coment this becose api routes with passport failed here.

        $this->clearLoginAttempts($request);

        return $this->authenticated($request, $this->guard()->user())
                ?: response()->json(["status"=>"error", "message"=>"Some error for failes authenticated method"]);

    }

    /**
     * Get the failed login response instance.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse
     */
    protected function sendFailedLoginResponse(Request $request)
    {
        return response()->json([
                                "status"=>"error", 
                                "message"=>"Autentication Error", 
                                "data"=>[
                                    "errors"=>[
                                        $this->username() => Lang::get('auth.failed'),
                                    ]
                                ]
                            ]);
    }

Если вы изменили логин: имя пользователя в поле пользовательского имени, например: e_mail. Вы должны уточнить метод имени пользователя, как в вашем LoginController. Также вам нужно переопределить и отредактировать методы: validateLogin, tryLogin, учетные данные, поскольку после подтверждения входа запрос отправляется в паспорт и должен называться username.

Ответ 3

Мне удалось заставить это работать с решением @RaymondLagonda для Laravel 5.5 с Sentinel, но оно также должно работать без Sentinel.

Для решения необходимо, чтобы некоторые методы класса переопределялись (поэтому, пожалуйста, имейте это в виду, для будущих обновлений) и добавляет некоторую защиту вашим маршрутам api (не подвергая, например, client_secret).

Первый шаг - изменить ваш ApiLoginController, чтобы добавить функцию построения:

public function __construct(Request $request){
        $oauth_client_id = env('PASSPORT_CLIENT_ID');
        $oauth_client = OauthClients::findOrFail($oauth_client_id);

        $request->request->add([
            'email' => $request->username,
            'client_id' => $oauth_client_id,
            'client_secret' => $oauth_client->secret]);
    }

В этом примере вам нужно определить var ('PASSPORT_CLIENT_ID') в вашем .env и создать OauthClients Model, но вы можете смело пропустить это, разместив здесь свои тестовые значения.

Одно замечание: мы устанавливаем значение $request->email для имени пользователя, просто придерживаемся соглашения Oauth2.

Второй шаг - переопределить метод sendLoginResponse, который вызывает ошибки, такие как Session storage not set, здесь нам не нужны сеансы, потому что это api.

protected function sendLoginResponse(Request $request)
    {
//        $request->session()->regenerate();

        $this->clearLoginAttempts($request);

        return $this->authenticated($request, $this->guard()->user())
            ?: redirect()->intended($this->redirectPath());
    }

Третий шаг - изменить ваши аутентифицированные методы, предложенные @RaymondLagonda. Вам нужно написать свою собственную логику и особенно настроить свои области.

И последний шаг (если вы используете Sentinel) - это изменить AuthServiceProvider. Добавить

$this->app->rebinding('request', function ($app, $request) {
            $request->setUserResolver(function () use ($app) {
                 return \Auth::user();
//                return $app['sentinel']->getUser();
            });
        });

сразу после $this->registerPolicies(); в методе загрузки.

После этих шагов вы сможете, чтобы получить работу api, указав имя пользователя ( "это всегда будет электронная почта, в этой реализации" ), пароль и grant_type = 'password'

В этот момент вы можете добавить в области middlewares scopes:... или scope:... для защиты ваших маршрутов.

Надеюсь, это действительно поможет...

Ответ 4

Я знаю, что это немного поздно, но если вы используете API-интерфейс backend в SPA, используя CreateFreshApiToken в промежуточном программном обеспечении Интернета, вы можете просто добавить в ваше приложение промежуточное программное обеспечение "admin":

php artisan make:middleware Admin

Затем в \App\Http\Middleware\Admin выполните следующее:

public function handle($request, Closure $next)
{
    if (Auth::user()->role() !== 'admin') {
        return response(json_encode(['error' => 'Unauthorised']), 401)
            ->header('Content-Type', 'text/json');
    }

    return $next($request);
}

Убедитесь, что вы добавили метод role в \App\User, чтобы получить роль пользователя.

Теперь все, что вам нужно сделать, это зарегистрировать ваше промежуточное ПО в app\Http\Kernel.php $routeMiddleware, например:

protected $routeMiddleware = [
    // Other Middleware
    'admin' => \App\Http\Middleware\Admin::class,
];

И добавьте это на свой маршрут в routes/api.php

Route::middleware(['auth:api','admin'])->get('/customers','Api\[email protected]');

Теперь, если вы попытаетесь получить доступ к api без разрешения, вы получите сообщение об ошибке "401 Unauthorized", которое вы можете проверить и обработать в своем приложении.