ハッピーメモメモ

私的備忘録

【Laravel】Laravel Sanctum-SPA認証➁ログイン

CSRF保護

■Vue

CSRF保護を初期化

 ・ SPAを認証するには、SPAの「ログイン」ページで最初に/sanctum/csrf-cookieエンドポイントにリクエストを送信して、アプリケーションのCSRF保護を初期化する必要がある

Login.vue

 
 await axios.get("/sanctum/csrf-cookie");

 

▼生成されたクッキーはネットワークのところでみれるよ

f:id:n-moeko1966:20220131161018p:plain

・エンドポイントにGETリクエストするとCSRFトークンを含むXSRF-TOKENクッキー付きレスポンスが返却される

→クッキー(正規のアクセスであることを証明する通行手形)がサーバー側で生成される!

・このクッキーに入っているトークンを X-XSRF-TOKEN ヘッダに入れてSPA側からリクエストする必要がある
(AxiosやAngular HttpClientなどの一部のHTTPクライアントライブラリでは自動的に行う)

 

 

〇SPA側のログイン画面

Login.vue

      const result = await axios.post("/api/login", {
        email: data.email,
        password: data.password,
      });

※このとき、「/api」をつけるのを忘れない!!

 「/login」へのルーティングを書いているのは、「api.php」だから

www.tairaengineer-note.com

 

■ルーティング

routes>api.php

<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Auth\CookieAuthenticationController;
 
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});
 
Route::post('/login', [CookieAuthenticationController::class, 'login']);

参考:

f:id:n-moeko1966:20220201144123p:plain

ルーティング 8.x Laravel

 

■Laravel

〇エンドポイント

・Laravel Sanctumをインストールした時点で下記エンドポイントが追加される

 GET|HEAD  | sanctum/csrf-cookie | Larave\Sanctum\Http\Controllers\CsrfCookieController@show | web  

→vendorフォルダの中に入ってる!

 

〇ログインコントローラー作成

<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class CookieAuthenticationController extends Controller
{
    public function login(Request $request)
  {
        $credentials = $request->validate([
            'email' => ['required', 'email'],
            'password' => ['required'],
        ]);

        // 認証が成功した場合の処理
        if (Auth::attempt($credentials)) {
            // セッションIDの再生成
            $request->session()->regenerate();
            return response()->json(['message' => 'Login successful']);
        }

        // 認証が失敗した場合の処理
        return response()->json(['message' => 'Login failure!'],401);
    }
}
 

 

・elseの回避

class ReplaceElse
{
    public function ifElse(bool $bool)
    {
        if ($bool === true) {
            return 'YES';
        }
        return 'NO';
    }
}

PHPでelseを書きたくない時に使える回避手段 - Qiita

 

・credentials

 資格、資格情報

 

・validateメソッド

 記述方法:

f:id:n-moeko1966:20220131220358p:plain

入門者のためのLaravelのバリデーションとエラーメッセージ | アールエフェクト

 

・attemptメソッド

 最初の引数:キー/値ペアの配列

 配列の値 :DBでユーザーを見つけるために使用

 処理   :ユーザーが見つかったらDBに保存しているハッシュ化したパスワードと

       配列でメソッドに渡したpassword値を比較する

       ※このときpassword値は自動的にハッシュ化される

 戻り値  :認証が成功したら「true」、それ以外の場合は「false」を返す

 

※このため、DBテーブルに保存されているパスワードはハッシュ化されている必要がある!!

ハッシュ化の仕方は2パターンある

PHPのpassword_hash() メソッドを使う方法

PHP: password_hash - Manual

②LaravelのLaravelの組み込みのHashファサードの呼び出し(こっち使うのが無難)

ハッシュ 8.x Laravel

        

・セッションIDの再生成

f:id:n-moeko1966:20220201095801p:plain


・リダイレクト

 書き方:

// httpの場合
return redirect('test/index');                
return redirect()->to('test/index');          
return redirect('test/index', 301);          
return redirect('test/index', 301, ['test-header' => 'テスト'] );

// httpsの場合
return redirect('test/index', 302, [], true);  

// ルート名での指定
return redirect()->route('test.list');
return redirect()->route('test.show', ['id' => 12]);    
$user = App\User::find(12);                              
return redirect()->route('test.show', ['id' => $test]);

// コントローラ名での指定
return redirect()->action('TestController@index');
return redirect()->action('TestController@show', ['id' => 12]);  

 

・intendedメソッド

(認証ミドルウェアによってインターセプトされる前に)アクセスしようとしたURLへユーザーをリダイレクトする

 

・認証後のリダイレクト先の書き換え

redirect()->intended($path)

→LoginControllerでセッションに保存した遷移前のURLに遷移できる?

 

・back()

return back()

→前の画面にリダイレクトする

 

・エラーメッセージのカスタマイズ

withInput() :送信されたフォームの値をそのまま引き継ぐ

       リダイレクトと同時に記録する?

withErrors() :発生したエラーメッセージをリダイレクト先まで引き継ぐ?

return Redirect::back()
->withInput()
->withErrors(array('ID' => 'エラー文言'));

laravelのwithErrorsでバリデーションエラー以外のエラー文言を渡す方法 - trtrakiのブログ

 

〇ログインコントローラー(パターン2)

public function login(Request $request): JsonResponse
{
    $credentials = $request->validate([
        'email' => ['required', 'email'],
        'password' => 'required',
    ]);

    if ($this->getGuard()->attempt($credentials)) {
        $request->session()->regenerate();

        return new JsonResponse(['message' => 'ログインしました']);
    }

    throw new Exception('ログインに失敗しました。再度お試しください');
}

 

・: JsonResponse

静的型付け言語における、型宣言みたいなもの

これは「JsonResponse」を返すよ!!と高らかに宣言してくれているので、

うまくいかなかったときにちゃんとエラーはいてくれそう

なくても動くよ

(参考記事が見つからなかったが、T先生より教授頂く)

 

・throw new Exception

中に入ったメッセージをVue側で見つけられず困惑したのだが、

Laravel側にいるのかも

基本的にVue側に渡したいものはreturnする必要がありそう

(参考記事が見つからなかったが、T先生より教授頂く)

 

 

 

 

 

 

 

 

 

 

 

readouble.com

 

qiita.com