A Laravel(Passport) - user000422/0 GitHub Wiki

概要

今なら読める https://supilog.supisupi.com/blog/jywu424ztuq4/

公式(Laravel 10): https://laravel.com/docs/11.x/passport ★★ 要注意ポイント ★★ 1台のサーバで検証する際はLaravelサーバを2つ起動すること。1つはデフォルトコマンド、2つ目はポート指定コマンド。

【かなり良い?】API認証(Passport)機能の動作確認 https://www.wakuwakubank.com/posts/457-laravel-passport/#index_id19 【ここもいい】Laravel 5.3 で Passportを試す https://blog.hinaloe.net/2016/09/15/try-passport-laravel-5-3/ PKCE https://qiita.com/okmt_okmt_/items/f70c7552b0ecba3375f6

Laravelアプリケーションに完全なOAuth2サーバー実装を数分で提供します。 Laravel Passportを実際に体験してみる https://qiita.com/miriwo/items/857ae5d156fcdec4c65a

PHP.iniの設定 … extension=sodium sodiumがなければ … dnf install php-sodium

Grant種類 説明
Password Grant 今後廃止予定。ユーザー名とパスワードを直接使ってトークンを発行。
Authorization Code Grant リダイレクトを通じてユーザーからの認可を得てトークンを発行
Client Credentials Grant アプリケーション自体が自分のクレデンシャルを使ってトークンを取得
Refresh Tokens 「アクセストークンの再発行」を行う。
テーブル 説明
oauth_clients Client情報(clientuser, client secret)(client_idはidカラム)
oauth_auth_codes 認証コード(アクセストークンではない)が格納される
oauth_access_tokens アクセストークンが格納される
oauth_auth_codesc

リフレッシュトークン 初期有効時間 : 1年

認証認可の知識

一例)https://christina04.hatenablog.com/entry/secure-token-management 認可サーバ … トークンを発行するだけのサーバ リソースサーバ … 取得したいデータが格納されているサーバ アクセストークンでアクセス可

認証(ログイン)後、認可サーバからアクセストークンが発行される。 アクセストークンはログイン等のレスポンスでクライアントに渡され、Cookie(またはローカルストレージなど)に保存される。 リフレッシュトークンも同様。 トークンは一般的にはブラウザのCookieで管理するのが主流である。 Cookieには「httpOnly属性」をTrueにすること。JavaScriptからCookieの値を参照大対策。 ローカルストレージには保持しないこと。

プログラム

cd [Laravelプロジェクト]

# インストール
# Laravel10までのコマンド 11からは別コマンド
composer require laravel/passport
composer require laravel/passport:^12.2 # バージョン指定
composer require laravel/passport:^11.10 # バージョン指定

# マイグレーション
php artisan migrate

# 設定ファイル、トークンを作成するために使用する暗号化キー、クライアントの作成
# storageディレクトリの中にoauth-private.key, oauth-public.keyという名前でキーが保存されます。
php artisan passport:install
# Q.Would you like to run all pending database migrations?
# yes
# Q.Would you like to create the "personal access" and "password grant" clients?
# Q.「personal access client」と「password grant client」を作成しますか?
# yes
# Authorization Code Grantの場合のクライアントの作成
php artisan passport:client --public

■【必須 共通】モデル(ユーザテーブル)の編集

use Laravel\Passport\HasApiTokens; // パスをpassportに変更

class User extends Authenticatable
{
    use Notifiable,HasApiTokens;
}

■AuthProvider.phpの編集 Laravel Passport11からは Passport::routes() の記述は不要。(記述したらエラー)

■【必須 共通】config/auth.phpの編集 編集後クリアすること php artisan config:clear

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'users', // 会員テーブル
    ],
],

■トークンを所持していない場合のリダイレクト先 ログイン画面のルートにnameを設定する。

// routes/web.php
Route::get('/login', [LoginController::class, 'index'])->name('login');

■【適切に設定】api.php ルーティングに対してAccessTokenによる認証ガードを設定。

//Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
Route::middleware('auth:api')->get('/sample', function (Request $request) {
    return $request->user();
});

■【動作確認済み】認可画面をスキップしたい場合

# まずはモデルを作成
mkdir /var/www/html/sample-app/app/Models/Passport
php artisan make:model Passport/Client
// model 編集
// 参考 : 公式github https://github.com/laravel/passport/blob/12.x/src/Client.php
use Laravel\Passport\Client as BaseClient;

class Client extends BaseClient
{
    public function skipsAuthorization(): bool
    {
        //return $this->firstParty();
        return true; // こっちにしとけば変な事故起きない
    }
}

■AuthServiceProvider AuthServiceProvider

public function boot(): void
{
    // 持続時間(Access Token)
    Passport::tokensExpireIn(now()->addSeconds(3600));
}

■CORS設定(要確認) 参考 : x config/cors.php

# 'paths' => ['api/*', 'sanctum/csrf-cookie'],
'paths' => ['api/*', 'sanctum/csrf-cookie', 'oauth/token/*'],

■Controller Password Grantの場合

// app/Providers/AppServiceProvider.php
// Passport 12 の場合は下記が必須
use Laravel\Passport\Passport;
public function boot(): void
{
    Passport::enablePasswordGrant();
}
use Illuminate\Support\Facades\Auth;

public function store(Request $request)
{
    // Auth::attempt ユーザテーブルでログイン認証(email, password)
    // 早期リターン
    if (!Auth::attempt($credentials)) {
        // ログイン失敗。
    }

    $user = Auth::user();

    // トークン作成(スコープなし)
    $tokenResult = $user->createToken('Personal Access Token');

    $token = $tokenResult->token;
    $token->save();

    return response()->json([
        'access_token' => $tokenResult->accessToken,
        'token_type' => 'Bearer',
        'expires_in' => $tokenResult->token->expires_at->diffInSeconds(now()),
        'refresh_token' => $tokenResult->token->id,
    ]);
}

ログアウト

■公式

use Laravel\Passport\TokenRepository;
use Laravel\Passport\RefreshTokenRepository;

$tokenRepository = app(TokenRepository::class);
$refreshTokenRepository = app(RefreshTokenRepository::class);

$tokenRepository->revokeAccessToken($tokenId);
$refreshTokenRepository->revokeRefreshTokensByAccessTokenId($tokenId);

■野良

$tokenIds = Passport::token()
    ->where('user_id', Auth::id())
    ->where('client_id', $clientId)
    ->where('revoked', false)
    ->get()
    ->pluck('id');

Passport::token()
    ->whereIn('id', $tokenIds)
    ->update(['revoked' => true]);

Passport::refreshToken()
    ->whereIn('access_token_id', $tokenIds)
    ->update(['revoked' => true]);

return response()->json();