ゆるふわLaravel勉強会 (認証/JWT) 認証に関する資料
Laravel 認証についての色々まとめ
以下の記事は 2019/4/1 コワーキングスペース秋葉原Weeybleで行われる輪読会 [秋葉原] ゆるふわLaravel勉強会 (認証/JWT)のための認証に関する資料となります。
内容は以下の有志によるリファレンスサイトの記事の要約となります。 Laravel 5.8 認証
また、バージョンはLaravel 5.8.8 を前提にしています。
認証クイックスタート
Laravelインストール直後は認証系がフロント側で動く状態にはなっていないが、Controller等は既に準備されている
Controllers/Auth
配下
コントローラー | 用途 |
---|---|
RegisterController | 新ユーザーの登録 |
LoginController | 認証処理 |
ForgotPasswordController | パスワードリセットのためのメールリンク処理 |
ResetPasswordController | パスワードリセット処理 |
ひとまず認証付きのアプリを作るには、まずは以下のコマンドを打って、フロント側やルーティングに認証系の処理を自動生成させる
php artisan make:auth
コマンドを叩くとファイルに記述が追加されたり、新規ファイルが作られたりする
もし認証付きのアプリケーションを作るのであればfirst commit直後位に実施してしまうのが良い
変化のあるファイルの紹介
ルーティング
routes/web.php
// 以下2行が追加される
Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');
Auth::routes();
で登録画面、ログイン画面、パスワードリセットのすべてのルーティングを設定してくれている、個別に編集が必要な場合は、この行を廃止して画面毎にルーティングを定義する。
HomeControllerの追加
app\Http\Controllers\HomeController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class HomeController extends Controller { /** * Create a new controller instance. * * @return void */ public function __construct() { $this->middleware('auth'); } /** * Show the application dashboard. * * @return \Illuminate\Contracts\Support\Renderable */ public function index() { return view('home'); } }
ルーティングの2行目に追加された処理を行うControllerだが、ログイン直後の画面のサンプル例となる。 ログインすると/home
に移動するので、アプリケーションの仕様に従い、表示を作り込めば良いし、Home
という名前が気に食わないなら随意に変更する
その他以下の各viewファイルが自動生成されます。
resources\views\home.blade.php
resources\views\auth\login.blade.php
resources\views\auth\register.blade.php
resources\views\auth\verify.blade.php
resources\views\auth\passwords\email.blade.php
resources\views\auth\passwords\reset.blade.php
resources\views\layouts\app.blade.php
ログイン・登録・パスワードリマインダ等のページと機能も自動で生成してほぼ機能するようになります。
ブラウザでルートのpathにアクセスすると、画面左上に[LOGIN]と[REGISTER]のリンクが表示されるようになります。
認証の動作確認
まずはDBが無いので作ります。(vagrant環境でMySQLがある前提)
$ mysql -u root -p secret mysql> create database your_database_name; mysql>exit
migrateしてDBにtableを作ります。
$ php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table
user table以外にpassword resetのtableもcreateされました。
これでREGISTER出来る様になりました。
登録画面に移動して、登録すると、DBにuserが生成され、ログインして/home
にリダイレクトされます。
当然一度ログアウトしてログインができることも確認できます。
また、ログイン画面にパスワードを忘れた際のMailリマインダ―がありますが、mailの設定をしないと飛びませんので、今回は割愛
以上が、クイックスタートで作られた認証の初期概要です。
認証のカスタマイズ (初級編)
初期状態は以下の様な認証の仕様となっていますが、これは簡単に変更が可能です。
以下はリファレンスサイトの内容をほぼ転載しています。
ログイン後のリダイレクト先 /home
の変更
LoginController
、RegisterController
、ResetPasswordController
、VerificationController
のredirectTo
プロパティで、認証後のリダイレクト先の場所を定義してください。
protected $redirectTo = '/';
ログイン時のEmailをユニークな username, user_id,等に変更する
ログイン時はemailとpasswordの組み合わせが認証のデフォルトだが、emailをuser_id等に変更したい場合。
これをカスタマイズしたい場合は、
LoginController
でusername
メソッドを定義してください。
public function username() { return 'user_id'; }
当然user Tableをmigrateして変更したいユニークとなるカラムを追加してください。
登録済みユーザーのロール別制限 guard メソッド
webアプリを普通に作ってる場合は個人的にあまり使いませんが、APIやSPAの際にはよく使う事になるそうです。
LoginController
、RegisterController
、ResetPasswordController
でguard
メソッドを定義してください。メソッドからガードインスタンスを返してください。
use Illuminate\Support\Facades\Auth; protected function guard() { return Auth::guard('guard-name'); }
認証済みユーザーの取得 -Authファサード超便利-
Auth::user()->email
とかでuser関連のデータをControllerやviewですぐ取得できる。
基本は認証時に行った user Tableのカラムのデータが取得できるので、自分のデータを取得したい際にとても便利に使えます。
use Illuminate\Support\Facades\Auth;
Auth::user()->email; // taro@gmail.com
認証中のユーザーか調べる -必須並みの便利機能-
Auth::check()
これも 認証してる/してない を簡単に切り替え判断できる。controllerでもviewでも使える。認証の有無で処理や表示を変える際に便利!よく使う。
use Illuminate\Support\Facades\Auth; if (Auth::check()) { // ログイン中の場合の処理 } else { // 非ログイン中の処理 }
認証済みのみ通すページをルーティングで指定
この辺はルーティングの説明時にも紹介した内容で、ルーティングrouter/
でチェーンメソッド->middleware('auth')
と書くと、認証時のみ有効となるルーティングとして定義できます。
Route::get('profile', function() {
// 認証済みのユーザーのみが入れる
})->middleware('auth');
それ以外でも例えばコントローラのコンストラクタでもmiddlewareメソッドを呼べる
public function __construct() { $this->middleware('auth'); }
認証回数制限
brute-force対策が最初から出来ている感じ?
Laravelの組み込みLoginControllerクラスを使用している場合、
Illuminate\Foundation\Auth\ThrottlesLogins
トレイトが最初からコントローラで取り込まれています。デフォルトでは何度も正しくログインできなかった後、一分間ログインできなくなります。制限はユーザーの名前/メールアドレスとIPアドレスで限定されます。
自前のユーザー認証 (中級編)
リファレンスにある内容を紹介する
app\Http\Controllers\Auth\LoginController.php
に
authenticate
メソッドを新たに定義する。
認証系のカスタマイズはvendor\laravel\framework\src\Illuminate\Foundation\Auth\AuthenticatesUsers.php
にあるメソッドをオーバーライドするのが応用編の入り口の様です。
ちなみに下記のIlluminate\Foundation\Auth\AuthenticatesUsers.php
内のauthenticated
メソッドの実体は空メソッドで、カスタマイズ専用のメソッドである事がわかります。
/** * The user has been authenticated. * * @param \Illuminate\Http\Request $request * @param mixed $user * @return mixed */ protected function authenticated(Request $request, $user) { // }
これを以下の様にLoginController.php
に追加で記述をします。
以下、リファレンスサイトの例を転載します。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class LoginController extends Controller { /** * 認証を処理する * * @param \Illuminate\Http\Request $request * * @return Response */ public function authenticate(Request $request) { $credentials = $request->only('email', 'password'); if (Auth::attempt($credentials)) { // 認証に成功した return redirect()->intended('dashboard'); } } }
ここで重要なのはAuth::attempt($credentials)
です。
これが認証するか否かを判定できる仕組みで、引数に渡すのはモデルのカラム名となります。
オレオレの実装例
public function authenticate(Request $request) { // login_id カラムは email + '@' + community_id(int) で構成されたユニークの文字列として登録時に保存された値、これでログイン認証を行う $login_id = $request->email . '@' . $request->community_id; $credentials = array( 'login_id' => $login_id, 'password' => $request->password, ); $request->validate([ 'email' => 'required|string|email|max:170', 'password' => 'required|string|min:6', ]); if (Auth::attempt($credentials)) { return redirect('/')->with('message', 'ログインしました'); } else { return redirect()->back()->withErrors(array('email' => 'E-mailかPasswordが正しくありません'))->withInput(); } }
Auth::attempt($credentials)
に渡す認証の値は追加が可能です。以下の様に認証時の条件を3つ以上に設定することができます。
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) { // ユーザーは存在しており、かつアクティブで、資格停止されていない }
以降の認証に関する記述はリファレンスサイトを参考にしてください。
これ以降はケースバイケースで使用するかも。といったものが多い印象です。
よくありそうなカスタマイズについての実例など
RegisterController のカスタマイズ
ユーザー登録を行う際のvalidator
とcreate
メソッドの変更が必要であれば変える。
この辺は大変解りやすいコードだし、見たまんまで弄ってしまって基本OKです。
バリデートの変更や、ユーザー登録時に発行すべきカラムのデータ等を生成します。ありがちなのはユーザーの権限を初期状態で追加する。等の処理を行う事になるかと思います。
app\Http\Controllers\Auth\RegisterController.php
抜粋
/** * Get a validator for an incoming registration request. * * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ protected function validator(array $data) { return Validator::make($data, [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], ]); } /** * Create a new user instance after a valid registration. * * @param array $data * @return \App\User */ protected function create(array $data) { return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), ]); }
認証カスタマイズ(オレオレ編)
実はAuth::user()
で呼べるのは通常,user Tableのカラムだけとなります。ところがアプリの仕様上 user Tableがユニークにならない様な場合は、Auth::user() で欲しい一意のユーザーのデータが取得できず、偉い苦労しました。
どんなことをやったかというと、この記事にあるような事をしました。
Laravel 認証カスタマイズ 複数tableを結合しての認証で Auth::user() に必要な値を入れる方法
Laravelの認証機能をカスタマイズして、認証時に3つのカラム条件で認証をし、さらに認証後にAuth::user() ファサードに複数tableからの値を取得できるようにしました。
という訳で後半はこれについて説明します。