Laravel+vueでなんか作る(Laravel基礎編③~承認・認証~)
Udemyの講座Vue 3 and Laravel: A Practical Guide with Dockerの備忘録。
インストラクターの英語には若干耳慣れない訛りがあるけど、それを言いだしたらアメリカ英語やイギリス英語も「そういう訛り」なわけで、いろんな英語を聴くのもリスニング学習よな~~と思いつつ聴いている
今回はLogin、User、Logoutなどの認証と承認に関わるメソッドを作るよ!
Laravel Sanctum
こう……フロントエンドのSPAからの……なんかクッキーとかJWTトークンとか、ログインとかログアウトとか、ああいうのを可能にするツールらしい。知らんけど。
なお後述するが、「ああいうの」を専門用語で「認証(Authentication)」と「承認(Authorization)」と言う。
ちなみに「Sanctum」とはラテン語で「聖所」の意味らしい。元中二病患者としてはこういうのゾクゾクしますな。
―――――というわけで †Sanctumをインストール† します――――
-
composer require laravel/sanctum
する -
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
する - Dockerのバックエンドに入り、
php artisan migrate
する。 - Userクラスで
HasApiTokens
をUse
する。
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasFactory, Notifiable, HasApiTokens;
protected $guarded = [];
protected $hidden = ["password"];
}
認証 ( Authentication )
認証 ( Authentication )というのは、アクセスしてきたユーザーが
本人か確認する手続きのこと。
Login
コントローラ内でLoginメソッドを作る
public function login(Request $req){
if(!Auth::attempt($req->only("email","password"))){
return response([
"error" => "invalid credentials"
],Response::HTTP_UNAUTHORIZED);
}
$user = Auth::user();
$token = $user->createToken("token")->plainTextToken;
return response([
"jwt"=>$token
]);
}
急に知らないクラスやそのプロパティがうじゃうじゃ出てきてビックリしたが、なんとなく各自役割は推察できないでもない。
たぶんAuth
クラスと言うのが認証に関わるクラスで、これのattempt()
というクラスを使うと認証ができるんだろう。デフォルトではemailとpasswordを使うっぽい。ここには一家言ないのでデフォルトの処理に従うことにする。
attempt()
に成功するとAuth::user()
でユーザーが取り出せるのだと思われる。まったく便利な機能だぜ……。
承認 ( Authorization )
認証に成功したユーザーに、各メソッドにアクセスする権限を行うことを「承認」と言うらしい。
これはRoutingのレイヤーで行うようだ。
Route::middleware('auth:sanctum')->group(
function () {
Route::get("user",[AuthController::class,"user"]);
});
group()
内の関数に追記したルートが、tokenを持っているとアクセス可能になるっぽい。
public function user(Request $req){
return $req->user();
}
そしてgroup()
内のメソッドでは、$req->user();
でアクセス中のユーザーが取り出せるっぽい。マジか?! Sanctumすげぇな……。
Cookie
しかし現在の認証方法にはそもそも問題がある。
どうも認証に関わるコードをフロントエンドにストアするのはセキュリティ上よろしくないそうだ。耳にタコが出来るほど聞いた割にはいまいち原理が理解出来ていない「jwtトークンのセキュリティホール」問題だ。
これをクリアするため、トークンをクッキーにストアする。なんでトークンにストアするとセキュリティ上の問題点がクリアされるのかは個人的には謎のままである。
public function login(Request $req){
if(!Auth::attempt($req->only("email","password"))){
return response([
"error" => "invalid credentials"
],Response::HTTP_UNAUTHORIZED);
}
$user = Auth::user();
$jwt = $user->createToken("token")->plainTextToken;
//トークンの変数名を「jwt」に変えたよ
$cookie = cookie(
"jwt",$jwt, 60 * 24
);
//cookie関数の引数は
//「トークン名、トークンにする値、トークンの寿命(分単位)」だよ
return response([
"jwt"=>$token,
"user"=>$user
])->withCookie($cookie);
//withCookieでクッキーを添付できるよ
}
なんとLaravelにはクッキー作成用の関数がアウトオブザボックスで付いてるらしい。マジか……。
さらにHttp/Middleware/Authenticate.php
に以下を追記する。
public function handle($req, Closure $next, ...$guards)
{
if($jwt = $req->cookie("jwt")){
$req->headers->set(
"Authorization",
"Bearer ".$jwt
);
}
$this->authenticate($req, $guards);
return $next($req);
}
どうやらcookieから拾ってきた「jwt」を$req
のヘッダにくっつけて、next()
の処理に回してるっぽい。なるほどね。
- 今までの処理 → jwtトークンをフロントエンドからの通信のヘッダにくっつけて直でコントローラに入れる
- 現在の処理 → トークンはcookieにくっつけ、ミドルウェアを通過する際リクエストのヘッダに追加し、コントローラに入れる
というわけか。ここら辺の処理はミドルウェアを積み重ねていくexpress.jsとかに感覚が似てる気がする(などと適当なことを言う)。
なお追記したhundle()関数は、Vendor\Framework\Src\Illuminate\Auth\Middleware\Authenticate
内の同名の関数を雛形にしてるよ
cors
SPAとAPIを通信させる際に、承認関係で問題になるのがcors。
PostmanからはログインできるけどSPAのフロントエンドからはなぜかログインできません! みたいなときは、大抵corsが問題になっている。
Laravelではconfig/cors
を一行いじれば一応SPAからのログインはできるっぽい。
でもherokuとかawsにデプロイしたとき絶対何か不具合が起きそうだよな……。
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
//ここをfalseからtrueにしてる
];
2021年7月22日追記
config/cors
でsupports_credentials
をtrueにする上記の方法だけでは、フロントエンドにcookieを渡すことが出来なくなってしまいました。一体なぜ!?
Chromeで通信を調べたところ、Set-Cookieが弾かれていたようです。
という訳で、セッションの設定を変更します。
//前略
'same_site' => 'none',
さらに、.envに以下の設定を入れる。
SESSION_SECURE_COOKIE=true
これでcookieをセットできるようになりました!
Logout
use Illuminate\Support\Facades\Cookie;
// ~ 中 略 ~
public function logout(){
$cookie = Cookie::forget("jwt");
return response([
"message" => "success"
])->withCookie($cookie);
}
ようは「即時期限切れのクッキーをwithCookie()で添付する」という処理らしい。フーン。
これでログインとログアウトができるようになりました。
Author And Source
この問題について(Laravel+vueでなんか作る(Laravel基礎編③~承認・認証~)), 我々は、より多くの情報をここで見つけました https://qiita.com/SkipEveryLunch/items/3bef041f845fe4ea6f7c著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .