以下のサイトを日本語にしてみました。(ページ全てを訳してはいません)
誤りがあったらご指摘いただけると嬉しいです。
Step 1: Laravelをインストールする
ここでは「backend」という名でプロジェクトを作成しています。
composer create-project laravel/laravel backend
Step 2: .envファイルの設定
SESSION_DOMAIN
とSANCTUM_STATEFUL_DOMAINS
を追加することがセキュリティのために推奨されます。
SESSION_DOMAIN
はセッションクッキーのドメインを設定し、セッションハイジャックやCSRF攻撃などのクッキーベースの攻撃を防ぐのに役立ちます。
ドメインを指定しない場合、Laravelはアプリケーションの現在のドメインを使用します。
SANCTUM_STATEFUL_DOMAINS
は、Laravel Sanctumで保護されたアプリケーションのエンドポイントへのステートフルなリクエストを許可するドメインのリストを指定します。
これは、クロスサイトリクエストフォージェリ(CSRF)攻撃を防ぐのに役立ちます。
SESSION_DOMAIN
とSANCTUM_STATEFUL_DOMAINS
を設定しない場合、Laravelはデフォルトでアプリケーションの現在のドメインを使用します。
しかし、アプリケーションが複数のドメインやサブドメインからアクセスされる場合は、セキュリティを強化するために、これらの変数を設定することをお勧めします。データベースの認証情報を入力し、
SESSION_DRIVER=cookie
を設定します。
SESSION_DRIVER=cookie
は、Laravelがセッションデータを保存するためにクッキーを使用していることを意味します。
ユーザーがLaravelアプリケーションにログインすると、セッションデータを保存するためにブラウザにクッキーが設定されます。
このクッキーは、その後のリクエストごとにサーバーに送り返され、Laravelはユーザーのセッションデータを取得し、リクエストにまたがって状態を維持することができます。セッションの保存にクッキーを使うことは、ウェブ・アプリケーションでは一般的な慣行です。
しかし、クッキーはクロスサイトスクリプティング(XSS)やクロスサイトリクエストフォージェリ(CSRF)のような特定のタイプの攻撃に対して脆弱である可能性があることに注意することが重要です。
Laravelには、これらのタイプの攻撃に対するビルトインの保護が含まれていますが、それでもリスクを認識し、適切なセキュリティ対策を講じることが重要です。
つまり、セキュリティに気をつけるためにSESSION_DOMAIN
とSANCTUM_STATEFUL_DOMAINS
を追加しましょうということです。
FRONTEND_URL=http://localhost:3000
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost:3000
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=full_stack_laravel_react_js
DB_USERNAME=root
DB_PASSWORD=
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=cookie
SESSION_LIFETIME=120
Step 3: Laravel Sanctumのファイルを更新する
app/Http/Kernal.php
app/Http/Kernal.php
ファイルを開き、$middlewareGroups
とapi
セクションの下にあるステートフルリクエスト用の\LaravelSanctum\HttpMiddleware\EnsureFrontendRequestsAreStateful::class
をコメント解除してください。
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
\EnsureFrontendRequestsAreStateful::class
は、Laravel Sanctumが提供するミドルウェア・クラスです。
このミドルウェアは、アプリケーションのフロントエンドからのリクエストがステートフルなリクエストとして扱われ、認証を必要とする保護されたルートにアクセスできるようにするために使用します。
このミドルウェアは、暗号化されたCSRFトークンを含むクッキーをレスポンスに追加し、フロントエンドが後続のリクエストごとにこのトークンを送り返すことを期待します。
このようにして、ミドルウェアはCSRFトークンをチェックし、リクエストしたユーザーを特定し、保護されたルートにアクセスできるようにします。
こちらはこちらのサイトの方がわかりやすいと思います。
EnsureFrontendRequestsAreStatefulクラスは、ざっくりと以下のような処理を行う
・セッションクッキーのセキュア設定を強制
・cookie のスコープ(参照・操作の権限)を HTTP リクエストに制限し、javascriptなどから直接参照・操作されないようにする
・クッキーの暗号化
・レスポンスにクッキー付与(\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class)
・セッションの開始
・laravel_sessionをレスポンスに追加
・CSRFトークンを検証する
config/cors.php
次に、config/cors.php
を開き、以下の部分をfalse
からtrue
に変更します。
'supports_credentials' => true
上記はLaravel Sanctumの設定オプションで、クロスサイトリクエストにクッキーやその他のクレデンシャル(証明書)を含めることができます。
異なるドメインやサブドメインにまたがってリクエストを行う場合、ブラウザはセキュリティ上の理由からリクエストをブロックすることがあります。
これはセイム・オリジン・ポリシーとして知られており、あるドメインのウェブページが別のドメインのリソースとどのように相互作用できるかを制限します。
クロスサイトリクエストを許可するには、CORS(Cross-Origin Resource Sharing)ヘッダーを使用します。
Laravel Sanctumは、EnsureFrontendRequestsAreStatefulというミドルウェアを提供し、Sanctumがクッキーで正しく動作するために必要なCORSヘッダーを設定します。
supports_credentials' => true
設定オプションは、Cookie やその他の認証情報をクロスサイトリクエストに含めるべきであることを示すために使用されます。
このオプションが false
に設定されている場合、CORS ヘッダはクレデンシャルを含まず、ブラウザはリクエストと共にクッキーやその他の認証情報を送信しません。
今回はフロントとAPIのドメインが異なるため、corsの設定が必要です。
この値をtrueにしてあげないと、異なるドメインからのリクエスト時にエラーになってしまいます。
Step 4: テーブルのmigrate
Laravel Sanctumを使用するために、追加のマイグレーションを作成する必要はありません。
マイグレーションを実行するだけなので、マイグレーションを実行するには、以下のコマンドを使用するだけです:
php artisan migrate
Step 5: Controllerの作成
以下のコマンドで新しいControllerを作成してください。
php artisan make:controller AuthController
make:controller
コマンドは、新しいコントローラクラスを生成するためのショートカットです。
php artisan make:controller AuthController
を実行すると、Laravelはapp/Http/Controllers
ディレクトリにAuthController.php
という新しいファイルを作成します。
このファイルには、認証ロジックの出発点として使用できるいくつかの基本的なメソッドを持つスケルトンコントローラクラスが含まれます。
Step 6: Rotesの作成
AuthController クラスを作成したら、 それを使用してアプリケーションの routes/api.php
ファイルでルートを定義します。たとえば、以下のコードのように AuthController の login メソッドに対応するログインルートを定義します
routes/api.php
を開き、以下のように記述してください。
<?php
use App\Http\Controllers\AuthController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "api" middleware group. Make something great!
|
*/
// Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
// return $request->user();
// });
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
Route::middleware('auth:sanctum')->group(function() {
Route::post('/logout', [AuthController::class, 'logout']);
Route::get('/user', [AuthController::class, 'user']);
});
auth:sanctum
ミドルウェアはLaravel Sanctumによって提供され、Sanctumによって生成されたAPIトークンを使用してリクエストを認証するために使用されます。
auth:sanctum
ミドルウェアを使用するルートにリクエストが行われると、Sanctumはリクエストに有効なAPIトークンが含まれているかどうかをチェックします。
トークンが有効な場合、リクエストの続行が許可されます。
トークンが無効または見つからない場合、リクエストは401 Unauthorized
レスポンスで拒否されます。
Step 7: Login & RegisterのRequests作成
以下のコマンドで新しいrequestを作成してください。
php artisan make:request RegisterRequest
php artisan make:request RegisterRequest
は、アプリケーションのapp/Http/Requests
ディレクトリにRegisterRequest
という新しいフォームリクエストクラスを生成するLaravelのコマンドです。
Laravelのフォームリクエストは、入力されたHTTPリクエストを検証するために使用されます。
リクエストと共に送信されたデータを検証するルールを定義し、アプリケーションが処理する前に、データが特定の要件を満たしていることを確認するために使用できます。
app/Http/Requests/RegisterRequest.php
を開き、以下のように記述してください。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;
class RegisterRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
*/
public function rules(): array
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email|max:255',
'password' => [
'required',
'string',
Password::min(8)->mixedCase()->numbers()->symbols()->uncompromised(),
'confirmed',
]
];
}
}
同様に、以下のコマンドで新しいrequestを作成してください。
php artisan make:request LoginRequest
app/Http/Requests/LoginRequest.php
を開き、以下のように記述してください。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class LoginRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
*/
public function rules(): array
{
return [
'email' => 'required|email|exists:users,email',
'password' => 'required|string',
];
}
}
Step 8: UserモデルのResourceの作成
以下のコマンドで新しいresourceを作成してください。
php artisan make:resource UserResource
Laravelのリソースクラスは、アプリケーションのモデルからJSONレスポンスで返せる形式にデータを変換するために使用されます。
これらは、レスポンスで返されるデータをカスタマイズする方法を提供し、機密情報を隠したり、関連するデータを含めたり、その他のデータ変換を実行するために使用できます。
make:resource
コマンドは、新しいリソースクラスを生成するためのショートカットです。
php artisan make:resource UserResource
を実行すると、Laravelはapp/Http/ResourcesディレクトリにUserResource.php
という新しいファイルを作成します。
このファイルには、JSONレスポンスで返すデータを定義するために使用できるtoArray
メソッドを持つスケルトンリソースクラスが含まれます。
app/Http/Resources/UserResource.php
を開き、以下のように記述してください。
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
Step 9: AuthControllerのすべてのメソッドを定義する
すべてのファイルが準備できたので、次は AuthController.php
ファイルですべてのメソッドを定義します。
以下に、ユーザー登録、ユーザーログイン、ユーザー情報の取得、ユーザーログアウトのメソッドを定義します。
<?php
namespace App\Http\Controllers;
use App\Http\Requests\LoginRequest;
use App\Http\Requests\RegisterRequest;
use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
// ユーザー登録
public function register(RegisterRequest $request) {
$data = $request->validated();
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
$token = $user->createToken('auth_token')->plainTextToken;
$cookie = cookie('token', $token, 60 * 24); // 1日
return response()->json([
'user' => new UserResource($user),
])->withCookie($cookie);
}
// ログイン
public function login(LoginRequest $request) {
$data = $request->validated();
$user = User::where('email', $data['email'])->first();
if (!$user || !Hash::check($data['password'], $user->password)) {
return response()->json([
'message' => 'メールアドレスかパスワードが正しくありません'
], 401);
}
$token = $user->createToken('auth_token')->plainTextToken;
$cookie = cookie('token', $token, 60 * 24);
return response()->json([
'user' => new UserResource($user),
])->withCookie($cookie);
}
// ログアウト
public function logout(Request $request) {
$request->user()->currentAccessToken()->delete();
$cookie = cookie()->forget('token');
return response()->json([
'message' => 'ログアウトしました'
])->withCookie($cookie);
}
// ユーザー情報取得
public function user(Request $request) {
return new UserResource($request->user());
}
}
ユーザー登録メソッドの説明
このコードはLaravelアプリケーションのAuthController
クラスのregister
メソッドで、新規ユーザーの登録を処理します。
このメソッドは最初に、リクエストのバリデーションルールを含む RegisterRequest
クラスを使用してリクエストデータをバリデートします。
バリデート後、このメソッドはバリデートされたデータで新しいユーザーを作成し、LaravelのHash
ファサードを使用してユーザーのパスワードを安全に暗号化して保存します。
ユーザーオブジェクトのcreateToken
メソッドは、今後のAPIリクエストの認証に使用される、ユーザーの新しいパーソナルアクセストークンを作成します。
トークンは、HTTPクッキーの作成に使用され、トークンおよびユーザー・データとともに、JSONオブジェクトとしてレスポンスに返されます。
UserResource
クラスは、ユーザーデータをレスポンスに適した形式に変換するために使用されます。
クッキーの有効期限は1日、または60 * 24
分に設定されています。
この方法により、ユーザーは各リクエストにアクセストークンを手動で含めることなく、複数のリクエストにわたって認証ステータスを維持することができます。
その代わりに、アクセストークンはHTTPクッキーに保存され、その後のリクエストごとに自動的に送信されます。
ログインメソッドの説明
このコードはLaravelアプリケーションのAuthController
クラスのログインメソッドで、ユーザー認証の処理を担当します。
このメソッドはまず、リクエストの検証ルールを含むLoginRequest
クラスを使用してリクエストデータを検証します。
バリデーションの後、このメソッドは User
モデルの where
メソッドを使用して、指定されたメールアドレスを持つユーザを見つけようとします。
ユーザが見つからない場合、または提供されたパスワードがユーザのハッシュ化されたパスワードと一致しない場合、電子メールまたはパスワードが間違っていることを示すメッセージとともに401 Unauthorized
レスポンスが返されます。
ユーザーの認証に成功すると、このメソッドは、ユーザー・オブジェクトの createToken
メソッドを使用して、そのユーザーの新しい個人アクセストークンを作成します。
このトークンを使用してHTTPクッキーが作成され、トークンとユーザ・データとともにJSONオブジェクトとしてレスポンスに返されます。
UserResource
クラスは、ユーザーデータをレスポンスに適した形式に変換するために使用されます。
クッキーの有効期限は1日、または60 * 24
分に設定されています。
この方法により、ユーザーは各リクエストにアクセストークンを手動で含めることなく、複数のリクエストにわたって認証ステータスを維持することができます。
その代わりに、アクセストークンはHTTPクッキーに保存され、その後のリクエストごとに自動的に送信されます。
ユーザー情報取得メソッドの説明
このコードはLaravelアプリケーションのAuthController
クラスのuser
メソッドで、認証されたユーザーのデータを返す役割を担っています。
このメソッドは、有効なユーザーセッションとそのセッションに関連付けられたアクセストークンを含むRequest
オブジェクトが渡されることを期待します。
リクエストオブジェクトの user
メソッドは、認証されたユーザーをセッションから取得するために使われます。
このメソッドは、認証されたユーザ・オブジェクトをコンストラクタに渡して、UserResource
クラスの新しいインスタンスを作成します。
UserResource
クラスは、ユーザデータをレスポンスに適した形式に変換するために使用され、通常、機密データや不要なデータを削除し、残りのデータをよりユーザフレンドリな方法でフォーマットします。
最後に、このメソッドは変換されたユーザーデータをJSONオブジェクトとして返します。
このアプローチは、ユーザのデータが認証されたユーザにのみ返され、クライアントに返される前に機密データがフィルタリングされることを保証します。
Step 10: リクエストごとにクッキートークンを設定する
ここが重要なステップです。
app/Http/Middleware/Authenticate.php
ファイルを編集します。
以下のコードを参照してください。
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*/
protected function redirectTo(Request $request): ?string
{
return $request->expectsJson() ? null : route('login');
}
public function handle($request, Closure $next, ...$guards) {
if ($token = $request->cookie('token')) {
$request->headers->set('Authorization', 'Bearer ' . $token);
}
$this->authenticate($request, $guards);
return $next($request);
}
}
このコードは、LaravelアプリケーションのAuthenticate
ミドルウェアのhandle
メソッドで、ユーザーリクエストの認証を担当します。
このメソッドには、$request
オブジェクトと $next
クロージャ、そしてオプションの $guards
パラメータを渡します。
$guards
パラメータは、リクエストの認証に使用する認証ガードを指定するために使用します。
このメソッドは、まずリクエストクッキーにユーザのアクセストークンが含まれているかどうかを調べます。
トークンが見つかった場合は、それをリクエストヘッダに追加します。
このメソッドは次に authenticate
メソッドを呼び出し、リクエストの実際の認証を実行します。
authenticate
メソッドは、ユーザが認証され、アクセストークンが有効であることを確認します。
認証に成功すると、メソッドは認証済みの $request
オブジェクトを使用して $next
クロージャをコールします。
これにより、リクエストはスタックの次のミドルウェアに進むことができます。
このアプローチは、リクエストクッキーに存在する場合、ユーザーのアクセストークンがリクエストに自動的に添付され、ユーザーに代わって機密性の高いアクションが実行される前に、ユーザーが適切に認証されることを保証します。
次に向けて
認証されたユーザの詳細を取得し、ログアウトするために、フロントエンドから明示的にベアラートークンを送信する必要はありません。
セキュアな方法を使用しているため、httpのみのクッキーをクライアントのブラウザのクッキーに保存し、セッションの詳細もサーバに保存しています。
そのため、リクエストが送信されるたびに、クッキーはクライアント側からサーバーに自動的に送信され、残りはサーバー側で処理されます。
次のパートでは、reactアプリを作成してこのAPIを利用する方法を紹介します。