Laravel Passport грант Flow для собственных приложений - PullRequest
0 голосов
/ 26 октября 2018

Я использую Laravel Passport , чтобы предоставить доступ к некоторым частям моего API сторонним приложениям.

Но я также использую свой собственный API через собственное приложение Native Android от первого лица. Итак, я просмотрел весь интернет на предмет лучшей практики в этом случае, но застрял, чтобы прийти к выводу.

Вот возможности, которые я нашел:

Возможность # 01

Я могу следить за потоком предоставления пароля пользователя .
В этом случае мне нужно передать client_secret и client_id на сервер авторизации. Чтобы сохранить их в безопасности, я не могу написать их в исходном коде моего мобильного приложения (APK-файлы декомпилируемы ...).

Итак, у меня есть 2 варианта.

Возможность № 01 - Выбор A

Прокси-сервер через мой собственный сервер и ввод секрета перед вызовом конечной точки oauth:

$proxy = Request::create('/oauth/token', 'post', [
    'grant_type' => 'password',
    'client_id' => 1,
    'client_secret' => 'myownclientsecretishere',
    'username' => $username,
    'password' => $password
]);
$proxy->headers->set('Accept', 'application/json');
$response = app()->handle($proxy);

Возможность # 01 - Выбор B

Введите секрет при вызове конечной точки oauth с помощью Middleware:

class InjectPasswordGrantSecret
{
    public function handle($request, Closure $next)
    {
        $request->request->add([
            'client_id' => 1,
            'client_secret' => 'myownclientsecretishere'
        ]);
        return $next($request);
    }
}

Это рабочие примеры, но они также жадны в ресурсах. Я попытался использовать Apache benchmark на моей локальной машине, и я получил что-то вроде 9 запросов в секунду.

Возможность # 02

Я могу выполнить Персональный доступ .
Это не похоже на стандарт в OAuth2 , оно позволяет нам создавать токен по любому пользовательскому маршруту, например так:

if (! auth()->attempt(compact('username', 'password'))) {
    return error_response(__('auth.failed'));
}
$user = auth()->user();
$token = $user->createToken(null)->accessToken;

Использование Apache benchmark Я получаю лучший результат (что-то вроде 30 запросов в секунду).

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

Мне действительно интересно, предназначено ли это решение для использования в производственной среде.

Изначально я использовал библиотеку JWT tymon , потому что у меня было только собственное приложение. Но теперь, когда мне нужно заставить его работать со сторонними и сторонними приложениями, я подумал, что OAuth2 (через Laravel Passport) будет хорошим решением ...

Я надеюсь, что кто-то может помочь мне с этим и объяснить, что может быть хорошим решением, чтобы заставить его работать безопасно и [не медленно] на производственных серверах.

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

OAuth2 - это стандарт, но реализации, выполняемые людьми, иногда могут отличаться, но в большинстве случаев это ничего не меняет в конце.
Например, использование oauth/token или myserver/mytokenroute в качестве выигранного пути маршрута 'Ничего не измените на то, что должен делать маршрут, при условии, что генерация токенов выполняется таким же образом.В другом примере, является ли маршрут необходимым client_secret или нет, это не важно, если он безопасно предоставлен (и не хранится на стороне клиента).

Итак, если вам нужен хороший контроль над потоками OAuth2,Вы можете создать собственную реализацию Laravel Passport маршрутов.

Сначала вы можете удалить Passport::route(); из метода AuthServiceProvider@boot, чтобы удалить доступ к маршрутам Passport, а затем создать только те маршруты, которые вам нужны (oauth /например, токен).

Затем создайте свой собственный контроллер, расширяющий Laravel\Passport\Http\Controllers\AccessTokenController, чтобы иметь возможность использовать некоторые функции, предоставляемые Laravel Passport.В этом контроллере вы можете создать столько методов, сколько вам нужно для ваших маршрутов.
Вот пример с token route:

use Laravel\Passport\Http\Controllers\AccessTokenController;
use Laravel\Passport\TokenRepository;
use Lcobucci\JWT\Parser as JwtParser;
use League\OAuth2\Server\AuthorizationServer;
use Psr\Http\Message\ServerRequestInterface;

class MyOAuthController extends AccessTokenController
{
    public function __construct(AuthorizationServer $server, TokenRepository $tokens, JwtParser $jwt)
    {
        parent::__construct($server, $tokens, $jwt);
    }

    public function token(ServerRequestInterface $request)
    {
        $data = $request->getParsedBody();
        // You can inject your secrets here
        $data['grant_type'] = 'password';
        $data['client_secret'] = 'SECRET-HERE';
        $data['client_id'] = 'ID HERE';
        return parent::issueToken($request->withParsedBody($data));
    }
}

Если вам нужно, вы также можете сохранить результат parent::issueToken в промежуточной переменной, чтобы использовать ее вместо возврата клиенту.

Затем объявите маршрут в вашем AuthServiceProvider@boot методе:

Route::post('/myserver/mytokenroute', '\App\Http\Controllers\MyOAuthController@token');

Не забудьте, что вы можете использоватьmiddlewares, я бы использовал это, чтобы ограничить запросы для одного клиента, например:

Route::middleware('throttle:10,1')->post('/myserver/mytokenroute', '\App\Http\Controllers\MyOAuthController@token');

При таком подходе вы не будете использовать прокси, и я считаю его лучше, чем Personal Access Token, потому что у вас лучшеуправление всеми другими потоками (код авторизации, поток обновления и т. д.)Если вам нужно определенное поведение, просто создайте новый метод и свяжите его с маршрутом, сохраняя исходный код чистым и централизованным в одном контроллере.

0 голосов
/ 08 ноября 2018

То, что я сделал раньше, реализовал мой собственный контроллер, который расширяет Laravel\Passport\Http\Controllers\AccessTokenController. Вы можете не только настроить этот контроллер для обработки создания токенов, но и добавить маршруты для обновления и отзыва токенов.

Например, у меня был метод create для отображения формы входа, метод store для создания токена доступа, метод refresh для использования токена обновления для обновления маркеров доступа с истекшим сроком действия и revoke метод отзыва предоставленного токена доступа и связанного токена обновления.

Я не могу предоставить точный код, поскольку проект не является открытым исходным кодом, но это быстрый пример контроллера с методом store:

use Illuminate\Http\Request;
use Psr\Http\Message\ServerRequestInterface;
use Laravel\Passport\Http\Controllers\AccessTokenController;

class MyAccessTokenController extends AccessTokenController
{
    public function store(Request $request, ServerRequestInterface $tokenRequest)
    {
        // update the request to force your grant type, id, secret, and scopes
        $request->request->add([
            'grant_type' => 'password',
            'client_id' => 'your-client-id',
            'client_secret' => 'your-client-secret',
            'scope' => 'your-desired-scopes',
        ]);

        // generate the token
        $token = $this->issueToken($tokenRequest->withParsedBody($request->request->all()));

        // make sure it was successful
        if ($token->status() != 200) {
            // handle error
        }

        // return the token
        return $token;
    }
}

Метод refresh в основном будет таким же, но grant_type будет refresh_token.

Метод revoke может получить токен пользователя с аутентификацией ($token = $request->user()->token(), отозвать его ($token->revoke()), а затем вручную просмотреть таблицу oauth_refresh_tokens для соответствующих токенов (access_token_id = $token->id) и обновите поле revoked до true.

Создайте несколько маршрутов для использования своего пользовательского контроллера, и все готово (примечание: для маршрута revoke потребуется промежуточное ПО auth:api).

...