私は Laravel Passport を使用して、APIの一部にサードパーティのアプリへのアクセスを許可しています。
しかし、私は自分のファーストパーティNative Android Appを介して自分のAPIも使用しています。そのため、この場合のベストプラクティスについてインターネット全体を調べましたが、結論。
ここに私が見つけた可能性があります:
User Credential Password Grant Flow に従います。
この場合、client_secret
およびclient_id
を許可サーバーに送信します。それらを安全に保つために、モバイルアプリケーションのソースコードにそれらを書き込むことはできません(APKはコンパイルできません...)。
したがって、私には2つの選択肢があります。
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);
ミドルウェアを使用してoauthエンドポイントを呼び出すときにシークレットを挿入します。
class InjectPasswordGrantSecret
{
public function handle($request, Closure $next)
{
$request->request->add([
'client_id' => 1,
'client_secret' => 'myownclientsecretishere'
]);
return $next($request);
}
}
これらは実際の例ですが、リソースにも貪欲です。ローカルマシンでApacheベンチマークを使用しようとしたところ、9リクエスト/第二。
Personal Access Grant をフォローできます。
これは OAuth2 の標準のようには見えません。これにより、次のようにカスタムルートを介してトークンを作成できます。
if (! auth()->attempt(compact('username', 'password'))) {
return error_response(__('auth.failed'));
}
$user = auth()->user();
$token = $user->createToken(null)->accessToken;
Apacheベンチマークを使用すると、より良い結果が得られます(30リクエスト/秒など)。
ただし、トークンの有効期間はデフォルトでは構成できず、1年に設定されています(カスタムプロバイダーを使用してこの有効期間を構成できるようにする回避策があることに注意してください)。
このソリューションが本番環境で使用されることを意図しているかどうか、私は本当に疑問に思っています。
最初は自分のアプリしか持っていなかったため、 JWT tymon ライブラリーを使用しました。しかし、私はそれをファーストパーティとサードパーティのアプリで動作させる必要があるので、OAuth2(Laravel Passport)が良い解決策になると思いました...
私は誰かがこれを手伝ってくれることを望み、それを本番サーバーで安全にそして[ゆっくりと]動作させるための良い解決策となることができるものを説明します。
OAuth2は標準ですが、人が行う実装は異なる場合がありますが、ほとんどの場合、最終的には何も変更されません。
たとえば、ルートパスとして_oauth/token
_または_myserver/mytokenroute
_を使用しても、トークンの生成が同じ方法で行われている限り、ルートが行うことに何も変更されません。別の例として、_client_secret
_がルートで必要かどうかは、それが安全に提供されている(クライアント側に格納されていない)場合は重要ではありません。
したがって、OAuth2フローを適切に制御する必要がある場合は、_Laravel Passport
_ルートの独自の実装を作成できます。
最初に、_AuthServiceProvider@boot
_メソッドからPassport::route();
を削除してPassportルートへのアクセスを削除し、必要なルート(たとえば、oauth/token)のみを作成します。
次に、_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');
_
ミドルウェアを使用できることを忘れないでください。たとえば、これを使用して単一のクライアントの要求を制限します。
_Route::middleware('throttle:10,1')->post('/myserver/mytokenroute', '\App\Http\Controllers\MyOAuthController@token');
_
このアプローチではプロキシを使用しないため、他のすべてのフロー(認証コード、更新フローなど)をより適切に制御できるため、_Personal Access Token
_を使用するよりも優れていると思います。特定の動作が必要な場合は、新しいメソッドを作成してそれをルートにリンクするだけで、ソースコードがクリーンで単一のコントローラーに集中化されます。
以前に行ったことは、_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
_ミドルウェアが必要です)。