メインコンテンツまでスキップ

ログイン認証

認証方式について

SaaS を含む Web アプリケーションでは、代表的な認証方式として以下の 2 つがあります。
・セッションベース認証
・トークンベース認証

SaaSus Platform では、トークンベース認証 を採用しています。
以下に、それぞれの認証方式について説明します。

認証の種類

セッションベース認証

セッションベース認証は、サーバ側で生成したセッションIDを使用してクライアントが認証を行う方式 です。
この方式の特徴として、ステートフルな通信が可能 である一方、トークンベース認証と比較してサーバの負荷が高くなる 点が挙げられます。 01

トークンベース認証

トークンベース認証は、トークンの情報を利用してクライアントが認証を行う方式 です。
この方式の特徴として、サーバ側で認証情報を保持する必要がないため、セッションベース認証と比較してサーバの負荷が低く、ステートレスな通信が可能である 点が挙げられます。 02

セッションベース認証とトークンベース認証の違い

セッションベース認証は、サーバ側で認証のための情報を保持する のに対し、トークンベース認証は サーバ側に認証情報を保持せず、トークンの検証のみで認証を行う という違いがあります。
また、トークンベース認証は、ユーザー数が増加した際のサーバ負荷がセッションベース認証よりも低く、よりスケーラブルなシステムを実現できる というメリットがあります。

SaaSus Platform における認証

SaaSus Platform では トークンベース認証 を採用しています。
トークンの生成および検証は、SaaSus Platform SDK を利用し、SaaSus Platform の API を呼び出すことで実施します。 03

認証タイミングについて

ログインが必要な処理を実行する場合、サーバがリクエストを受けたタイミングで認証を行う必要があります。

SaaSus Platform では、SaaSus Platform SDK を利用し、リクエストごとに認証を実施します。
SDK の ユーザー情報取得処理 を実行することで、以下の情報を取得できます。
・トークンの検証
・ログインユーザの情報取得(ユーザ情報、テナント情報、権限)

ログインが必要な処理が複数ある場合、各処理の先頭で SaaSus Platform SDK を利用し、ユーザー情報を取得することで、ログイン状態を確認する必要があります。 04

処理数が増えると、個別に認証処理を実装することが困難になるため、フレームワークのミドルウェア機能を活用し、一律で認証をチェックする仕組みを導入することを推奨します。 05

トークンの種類

SaaSus Platform では、以下の3種類のトークンを生成します。
・IDトークン
・アクセストークン
・リフレッシュトークン

IDトークン

IDトークンは認証のために使用するトークンであり、有効期限は1時間です。
有効期限を過ぎるとトークンは無効となり、SaaS 利用者はログアウト状態となります。

// Laravelの場合、ルーティングファイルで SaaSus SDK 標準の Auth Middleware を利用する
// ルーティングは、SaaSus Platformで認証が必要な機能を記載する
Route::middleware(\AntiPatternInc\Saasus\Laravel\Middleware\Auth::class)->group(function () {
Route::get('/userinfo', [IndexController::class, 'userinfo']);
Route::get('/users', [IndexController::class, 'users']);
Route::get('/tenant_attributes', [IndexController::class, 'tenantAttributes']);
Route::get('/user_attributes', [IndexController::class, 'userAttributes']);
Route::post('/user_register', [IndexController::class, 'userRegister']);
Route::delete('/user_delete', [IndexController::class, 'userDelete']);
Route::get('/delete_user_log', [IndexController::class, 'deleteUserLog']);
Route::get('/pricing_plan', [IndexController::class, 'pricingPlan']);
Route::get('/tenant_attributes_list', [IndexController::class, 'tenantAttributesList']);
Route::post('/self_sign_up', [IndexController::class, 'selfSignUp']);
Route::post('/logout', [IndexController::class, 'logout']);
});

リフレッシュトークン

ログイン時間を長くする必要がある場合は、リフレッシュトークンを使用し、IDトークンを再生成することで、継続的なログインを実現できます。
リフレッシュトークンの有効期限は1ヶ月です。

public function refresh(Request $request)
{
// リフレッシュトークンを取得
$refreshToken = $request->cookie('SaaSusRefreshToken');
if (!is_string($refreshToken)) {
return response('Refresh token not found', Response::HTTP_BAD_REQUEST);
}

try {
$authClient = $this->client->getAuthClient();

// 第1引数は一時コードを設定するため、Blankを指定
// 第2引数に認証フローを refreshTokenAuth に設定し、第3引数にCookieから取得したリフレッシュトークンを設定する
$response = $authClient->getAuthCredentials([
'',
'refreshTokenAuth',
$refreshToken
]);

return response()->json($response->getBody());
} catch (\Exception $e) {
return response('Error occurred', Response::HTTP_INTERNAL_SERVER_ERROR);
}
}

アクセストークン

アクセストークンは、認可が必要な機能を利用する際に必要となるトークンです。
例えば、テナントへのユーザー招待機能など、特定の権限が求められる機能で使用されます。

    // リクエストから情報を取得
$email = $request->input('email');
$tenantId = $request->input('tenantId');
if (!$email || !$tenantId) {
return response()->json(['message' => 'Missing required fields'], Response::HTTP_BAD_REQUEST);
}

// UserInfoを取得
$userInfo = $request->userinfo;
if (!$userInfo) {
return response()->json(['detail' => 'No user'], Response::HTTP_BAD_REQUEST);
}

try {
// 招待を作成するユーザーのアクセストークンを取得
$accessToken = $request->header('X-Access-Token');

// アクセストークンがリクエストヘッダーに含まれていなかったらエラー
if (empty($accessToken)) {
return response()->json(['error' => 'Access token is missing'], 401);
}

// テナント招待のパラメータを作成
$createTenantInvitationParamEnvsItem = new CreateTenantInvitationParamEnvsItem();
$createTenantInvitationParamEnvsItem
->setId(3) // 本番環境のid:3を指定
->setRoleNames(['admin']);
$createTenantInvitationParam = new CreateTenantInvitationParam();
$createTenantInvitationParam
->setEmail($email)
->setAccessToken($accessToken)
->setEnvs([$createTenantInvitationParamEnvsItem]);

// テナント招待のAPIをCallする
$authClient = $this->client->getAuthClient();
$authClient->createTenantInvitation(
$tenantId,
$createTenantInvitationParam
);

return response()->json(['message' => 'Create tenant user invitation successfully']);
} catch (\Exception $e) {
Log::error($e->getMessage());
return response()->json(['detail' => $e->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
}