Настройка ответа на токен Laravel Passport

В настоящий момент я работаю над API и попал в кирпичную стену. Я использую Passport с типом типа "Пароль".

Я хочу вернуть информацию пользователя с помощью токенов доступа, однако я не уверен, как это сделать.

Какой класс я могу реализовать, отредактировать или расширить, чтобы получить это?

Я бы хотел, чтобы это было возвращено:

{
    "token_type": "Bearer",
    "expires_in": 31536000,
    "access_token": "lalalalalal",
    "refresh_token": "lalalallala",
    "user": {
        "username": "a username",
        "user_type": "admin"
    }
}

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

Ответ 1

Инструкции о том, как это сделать, описаны в классе BearerTokenResponse (входит в пакет league/oauth2-server).

Проверено на Laravel 5.7.

1. Расширьте класс BearerTokenResponse, добавьте в ответ дополнительные параметры, которые вам нужны.

namespace App\Auth;

use League\OAuth2\Server\Entities\AccessTokenEntityInterface;

class BearerTokenResponse extends \League\OAuth2\Server\ResponseTypes\BearerTokenResponse
{
    /**
     * Add custom fields to your Bearer Token response here, then override
     * AuthorizationServer::getResponseType() to pull in your version of
     * this class rather than the default.
     *
     * @param AccessTokenEntityInterface $accessToken
     *
     * @return array
     */
    protected function getExtraParams(AccessTokenEntityInterface $accessToken): array
    {
        return [
            'user_id' => $this->accessToken->getUserIdentifier(),
        ];
    }
}

2. Создайте свой собственный класс PassportServiceProvider и переопределите метод makeAuthorizationServer(), чтобы передать свой собственный класс BearerTokenResponse.

namespace App\Providers;

use App\Auth\BearerTokenResponse;
use Laravel\Passport\Bridge;
use League\OAuth2\Server\AuthorizationServer;

class PassportServiceProvider extends \Laravel\Passport\PassportServiceProvider
{
    /**
     * Make the authorization service instance.
     *
     * @return \League\OAuth2\Server\AuthorizationServer
     */
    public function makeAuthorizationServer()
    {
        return new AuthorizationServer(
            $this->app->make(Bridge\ClientRepository::class),
            $this->app->make(Bridge\AccessTokenRepository::class),
            $this->app->make(Bridge\ScopeRepository::class),
            $this->makeCryptKey('private'),
            app('encrypter')->getKey(),
            new BearerTokenResponse() // <-- The class you created above
        );
    }
}

3. Добавьте вашего провайдера в массив провайдеров в config/app.php

    /*
     * Application Service Providers...
     */
    App\Providers\PassportServiceProvider::class,

4. Исключите паспортный пакет из автоматического обнаружения laravel в composer.json

Это останавливает загрузку класса PassportServiceProvider по умолчанию.

    "extra": {
        "laravel": {
            "dont-discover": [
                "laravel/passport"
            ]
        }
    },

Затем запустите composer install.

Ответ 3

Два шага.

1. Добавить новый маршрут в файл маршрутов.

// routes/api.php

Route::post('oauth/token', '[email protected]');

Помните, что это изменит маршрут для получения токена от /oauth/token до /api/oauth/token.

2. Добавить метод контроллера.

<?php
// app/Http/Controllers/AuthController.php

namespace App\Http\Controllers;

use App\User;
use Psr\Http\Message\ServerRequestInterface;
use \Laravel\Passport\Http\Controllers\AccessTokenController;

class AuthController extends AccessTokenController
{
    public function auth(ServerRequestInterface $request)
    {
            $tokenResponse = parent::issueToken($request);
            $token = $tokenResponse->getContent();

            // $tokenInfo will contain the usual Laravel Passort token response.
            $tokenInfo = json_decode($token, true);

            // Then we just add the user to the response before returning it.
            $username = $request->getParsedBody()['username'];
            $user = User::whereEmail($username)->first();
            $tokenInfo = collect($tokenInfo);
            $tokenInfo->put('user', $user);

            return $tokenInfo;
    }
}

Ответ 4

Я использую Multi-Auth с паспортом, поэтому предыдущие ответы мне не помогли.

После нескольких часов "поиска в Google" я нашел этот ответ (after-) middleware.

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

<?php

namespace App\Http\Middleware;

use Closure;

class AppendTokenResponse
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {

        $response =  $next($request);

        $content = json_decode($response->content(), true);

        if (!empty($content['access_token'])) {

            $content['moredata'] = 'some data';

            $response->setContent($content);

        }

        return $response;
    }
}

Теперь поместите новое промежуточное ПО в $ routemiddleware в App/Http/Kernel.php

 /**
     * The application route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'cors' => \App\Http\Middleware\Cors::class,
        'multiauth' => \SMartins\PassportMultiauth\Http\Middleware\MultiAuthenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'oauth.providers' => \SMartins\PassportMultiauth\Http\Middleware\AddCustomProvider::class,
        'append_auth' =>\App\Http\Middleware\AppendTokenResponse::class,

    ];

Затем просто зарегистрируйте это промежуточное ПО для паспортных маршрутов в Providers/AuthServiceProvider.php

С MultiAuth:

Route::group(['middleware' => ['oauth.providers','append_auth']], function () {
    Passport::routes(function ($router) {
        return $router->forAccessTokens();
    });
});

Я считаю, что обычный паспорт должен быть (не проверен):

Route::group(['middleware' => ['append_auth']], function () {
    Passport::routes();
});

Ответ 5

Вы можете легко это сделать. Откройте файл BearerTokenResponse.php расположенный в vendor\league\oauth2-server\src\ResponseTypes

Измените метод generateHttpResponse (ResponseInterface $response) следующим образом:

public function generateHttpResponse(ResponseInterface $response)
    {
        $expireDateTime = $this->accessToken->getExpiryDateTime()->getTimestamp();

        $jwtAccessToken = $this->accessToken->convertToJWT($this->privateKey);

        $responseParams = [
            'token_type'   => 'Bearer',
            'expires_in'   => $expireDateTime - (new \DateTime())->getTimestamp(),
            'access_token' => (string) $jwtAccessToken,
            'user' => User::find($this->accessToken->getUserIdentifier()),
        ];

        if ($this->refreshToken instanceof RefreshTokenEntityInterface) {
            $refreshToken = $this->encrypt(
                json_encode(
                    [
                        'client_id'        => $this->accessToken->getClient()->getIdentifier(),
                        'refresh_token_id' => $this->refreshToken->getIdentifier(),
                        'access_token_id'  => $this->accessToken->getIdentifier(),
                        'scopes'           => $this->accessToken->getScopes(),
                        'user_id'          => $this->accessToken->getUserIdentifier(),
                        'expire_time'      => $this->refreshToken->getExpiryDateTime()->getTimestamp(),
                    ]
                )
            );

            $responseParams['refresh_token'] = $refreshToken;
        }

        $responseParams = array_merge($this->getExtraParams($this->accessToken), $responseParams);

        $response = $response
            ->withStatus(200)
            ->withHeader('pragma', 'no-cache')
            ->withHeader('cache-control', 'no-store')
            ->withHeader('content-type', 'application/json; charset=UTF-8');

        $response->getBody()->write(json_encode($responseParams));

        return $response;
    }

Не забудьте использовать модель App\User.

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