イントロダクション
lightbulb”>Tip!! さっさと始めたいですか? インストールしたてのLaravelアプリケーションで
php artisan make:auth
とphp artisan migrate
を実行するだけです。それから、ブラウザでhttp://your-app.dev/register
、もしくはアプリケーションに割りつけたその他のURLへアクセスしてください。この2つのコマンドが、認証システム全体のスカフォールドを面倒みます。
Laravelでは簡単に認証が実装できます。実際ほとんど全て最初から設定済みです。認証の設定ファイルはconfig/auth.php
に用意してあり、認証サービスの振る舞いを調整できるように、読みやすいコメント付きでたくさんのオプションが用意されています。
Laravelの認証機能は「ガード」と「プロバイダ」を中心概念として構成されています。ガードは各リクエストごとに、どのようにユーザを認証するかを定義します。たとえば、Laravelにはセッションストレージとクッキーを使いながら状態を維持するsession
ガードが用意されています。
プロバイダは永続ストレージから、どのようにユーザを取得するかを定義します。LaravelはEloquentとデータベースクリエビルダを使用しユーザを取得する機能を用意しています。しかし、アプリケーションの必要性に応じて、自由にプロバイダを追加できます。
混乱しても心配ありません。通常のアプリケーションでは、デフォルトの認証設定を変更する必要はありません。
データベースの検討事項
デフォルトととしてLaravelは、App\User
Eloquentモデルをapp
ディレクトリに用意しています。このモデルはデフォルトEloquent認証ドライバで使用しています。もしアプリケーションでEloquentを使用しなければ、Laravelクエリビルダを使用するdatabase
認証ドライバを使用する必要があります。
App\User
モデルのデータベーススキマー構築時に、確実にパスワードカラムを最低60文字確保してください。デフォルトの255文字にするのが、良い方法でしょう。
さらにusers
、もしくは同等の働きをするテーブルには、100文字のremember_token
文字列カラムも含めてください。このカラムはログイン時に、アプリケーションで”remember me”を選んだユーザのトークンを保存しておくカラムとして使用されます。
認証 Quickstart
App\Http\Controllers\Auth
名前空間下に多くの組み込み済み認証コントローラがLaravelにより用意されています。RegisterController
は新ユーザの登録、LoginController
は認証処理、ForgotPasswordController
はパスワードリセットのためのメールリンク処理、ResetPasswordController
はパスワードリセット処理を行います。各コントローラは必要なメソッドを含むトレイトを使用しています。多くのコントローラでは、これらのコントローラを変更する必要は全くありません。
ルート定義
簡単なコマンド一つで、認証に必要となるルート定義とビューをすべてスカフォールディングできる、簡単な手段をLaravelは提供しています。
php artisan make:auth
このコマンドは新しくインストールしたアプリケーションでのみ実行すべきで、レイアウトビュー、登録ログインビューをインストールし、同時にすべての認証エンドポイントのルートも定義します。HomeController
も、ログイン後に必要となる、アプリケーションのダッシュボードのために生成されます。
ビュー
前のセクションで説明したとおり、php artisan make:auth
コマンドはresources/views/auth
ディレクトリへ、認証に必要なすべてのビューを生成します。
make:auth
コマンドはresources/views/layouts
ディレクトリにアプリケーションのベースレイアウトビューも生成します。これらのビューはすべてBootstrap CSSフレームワークを使用していますが、自由にカスタマイズしてください。
認証
これで、認証コントローラを含め、必要なルートとビューの準備が整いました。アプリケーションに新しいユーザを登録し、認証できるようになりました。ブラウザでアプリケーションへアクセスしてください。認証コントローラは(内部で使用しているトレイトにより)、既存ユーザの認証と、新しいユーザをデータベースへ保存するロジックをすでに備えています。
パスのカスタマイズ
ユーザが認証に成功すると、/home
のURIへリダイレクトします。これをカスタマイズするには、LoginController
、RegisterController
、ResetPasswordController
のredirectTo
プロパティで、認証後のリダイレクト先の場所を定義してください。
protected $redirectTo = '/';
ユーザが認証に失敗した場合、自動的にログインフォームへリダイレクトします。
ガードのカスタマイズ
更に、登録済みユーザを認証するために使用する「ガード」をカスタマイズすることも可能です。LoginController
、 RegisterController
、ResetPasswordController
でguard
メソッドを定義してください。メソッドからガードインスタンスを返してください。
use Illuminate\Support\Facades\Auth;
protected function guard()
{
return Auth::guard('guard-name');
}
バリデーション/保管域のカスタマイズ
アプリケーションに新しいユーザを登録する場合に入力してもらうフォームのフィールドを変更するか、データベースに新しいユーザレコードを登録する方法をカスタマイズしたい場合は、RegisterController
クラスを変更してください。このクラスはアプリケーションで新しいユーザのバリデーションと作成に責任を持っています。
RegisterController
のvalidator
メソッドはアプリケーションの新しいユーザに対するバリデーションルールで構成されています。このメソッドはお気に召すまま自由に変更してください。
RegisterController
のcreate
メソッドは新しいApp\User
レコードをEloquent ORMを使用し、データベースに作成することに責任を持っています。データベースの必要に合わせて自由にこのメソッドを変更してください。
認証済みユーザの取得
Auth
ファサードを使えば認証済みユーザへ簡単にアクセスできます。
use Illuminate\Support\Facades\Auth;
$user = Auth::user();
もしくは、ユーザが認証済みであれば、Illuminate\Http\Request
インスタンス経由で、ユーザへアクセスすることもできます。コントローラメソッドでタイプヒントしたクラスは、自動的にインスタンスが依存注入されることを思い出してください。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
/**
* ユーザプロフィールの更新
*
* @param Request $request
* @return Response
*/
public function update(Request $request)
{
// $request->user()は認証済みユーザのインスタンスを返す
}
}
現在のユーザが認証されているか調べる
ユーザが既にアプリケーションにログインしているかを調べるには、Auth
ファサードのcheck
メソッドが使えます。認証時にtrue
を返します。
use Illuminate\Support\Facades\Auth;
if (Auth::check()) {
// ユーザはログインしている
}
lightbulb”>Tip!!
check
メソッドを使っても、あるユーザが認証済みであるかを判定可能です。特定のルートやコントローラーへユーザをアクセスさせる前に、認証済みであるかをミドルウェアにより確認する場合、典型的に使用します。より詳細についてはルートの保護のドキュメントを参照してください。
ルートの保護
ルートミドルウェアは特定のルートに対し、認証済みユーザのみアクセスを許すために使われます。LaravelにはIlluminate\Auth\Middleware\Authenticate
の中で定義されているauth
ミドルウェアが最初から用意されています。このミドルウェアは、HTTPカーネルで登録済みのため、必要なのはルート定義でこのミドルウェアを指定するだけです。
Route::get('profile', function() {
// 認証済みのユーザのみが入れる
})->middleware('auth');
もちろんコントローラーを使っていれば、ルート定義に付加する代わりに、コントローラーのコンストラクターでmiddleware
メソッドを呼び出すことができます。
public function __construct()
{
$this->middleware('auth');
}
ガードの指定
auth
ミドルウェアをルートに対し指定するときに、そのユーザに対し認証を実行するガードを指定することもできます。指定されたガードは、auth.php
設定ファイルのguards
配列のキーを指定します。
public function __construct()
{
$this->middleware('auth:api');
}
認証回数制限
Laravelの組み込みLoginController
クラスを使用している場合、Illuminate\Foundation\Auth\ThrottlesLogins
トレイトが最初からコントローラで取り込まれています。デフォルトでは何度も正しくログインできなかった後、一分間ログインできなくなります。制限はユーザの名前/メールアドレスとIPアドレスで限定されます。
自前のユーザ認証
もちろん、Laravelに含まれる認証コントローラーを使うことを強要しているわけでありません。これらのコントローラーを削除する選択肢を選ぶのなら、Laravel認証クラスを直接使用しユーザの認証を管理する必要があります。心配ありません。それでも簡単です!
Laravelの認証サービスにはAuth
ファサードでアクセスできます。クラスの最初でAuth
ファサードを確実にインポートしておきましょう。次にattempt
メソッドを見てみましょう。
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
/**
* 認証を処理する
*
* @return Response
*/
public function authenticate()
{
if (Auth::attempt(['email' => $email, 'password' => $password])) {
// 認証に成功した
return redirect()->intended('dashboard');
}
}
}
attempt
メソッドは最初の引数として、キー/値ペアの配列を受け取ります。配列中の他の値は、データベーステーブルの中からそのユーザを見つけるために使用されます。ですから、上の例ではemail
カラムの値により、ユーザが取得されます。ユーザが見つかれば、配列でメソッドに渡されたハッシュ済みのpassword
値と、データベースに保存してあったハッシュ済みpassword
が比較されます。2つのハッシュ済みパスワードが一致したら、そのユーザの新しい認証セッションが開始されます。
attempt
メソッドは、認証が成功すればtrue
を返します。失敗時はfalse
を返します。
リダイレクタ―のintended
メソッドは、認証フィルターにかかる前にアクセスしようとしていたURLへ、ユーザをリダイレクトしてくれます。そのリダイレクトが不可能な場合の移動先として、フォールバックURIをこのメソッドに指定してください。
追加条件の指定
お望みであれば、ユーザのメールアドレスとパスワードに付け加え、認証時のクエリに追加の条件を指定することも可能です。
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// ユーザは存在しており、かつアクティブで、資格停止されていない
}
Note: note この例のように、
特定のGuardインスタンスへのアクセス
Auth
ファサードのguard
メソッドにより、使用したいガードインスタンスを指定できます。これにより全く異なった認証用のモデルやユーザテーブルを使い、アプリケーションの別々の部分に対する認証を管理することができます。
guard
メソッドへ渡すガード名は、auth.php
認証ファイルのguards設定の一つと対応している必要があります。
if (Auth::guard('admin')->attempt($credentials)) {
//
}
ログアウト
アプリケーションからユーザをログアウトさせるには、Auth
ファサードのlogout
メソッドを使用してください。これはユーザセッションの認証情報をクリアします。
Auth::logout();
継続ログイン
アプリケーションでログイン維持(Remember me)機能を持たせたい場合は、attempt
メソッドの第2引数に論理値を指定します。ユーザが自分でログアウトしない限り、認証が無期限に持続するようになります。もちろん、”remember me”トークンを保存するために使用する文字列のremember_token
カラムをusers
テーブルに持たせる必要があります。
if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
// このメンバーは継続ログインされる
}
lightbulb”>Tip!! Laravelに用意されている、組み込み
LoginController
を使用する場合、このコントローラが使用しているトレイトにより、”remember”ユーザを確実に処理するロジックが実装済みです。。
この機能を使用している時に、ユーザが”remember me”クッキーを使用して認証されているかを判定するには、viaRemember
メソッドを使用します。
if (Auth::viaRemember()) {
//
}
他の認証方法
Userインスタンスによる認証
既に存在しているユーザインスタンスでアプリケーションにログインさせる必要があれば、login
メソッドにそのユーザインスタンスを指定し呼び出してください。指定されたオブジェクトはIlluminate\Contracts\Auth\Authenticatable
契約を実装している必要があります。もちろん、Laravelが用意しているApp\User
モデルはこのインターフェイスを実装しています。
Auth::login($user);
// 指定したユーザでログインし、"remember"にする
Auth::login($user, true);
もちろん、使用したいガードインスタンスを指定することもできます。
Auth::guard('admin')->login($user);
IDによるユーザ認証
ユーザをアプリケーションへIDによりログインさせる場合は、loginUsingId
メソッドを使います。このメソッドは認証させたいユーザの主キーだけを引数に受け取ります。
Auth::loginUsingId(1);
// 指定したユーザでログインし、"remember"にする
Auth::loginUsingId(1, true);
ユーザを一度だけ認証する
once
メソッドを使用すると、アプリケーションにユーザをそのリクエストの間だけログインさせることができます。セッションもクッキーも使用しないため、ステートレスなAPIを構築する場合に便利です。
if (Auth::once($credentials)) {
//
}
HTTP基本認証
HTTP基本認証により、専用の「ログイン」ページを用意しなくても手っ取り早くアプリケーションにユーザをログインさせられます。これを使用するには、ルートにauth.basic
ミドルウェアを付けてください。auth.basic
ミドルウェアはLaravelフレームワークに含まれているので、定義する必要はありません。
Route::get('profile', function() {
// 認証済みのユーザのみが入れる
})->middleware('auth.basic');
ミドルウェアをルートに指定すれば、ブラウザーからこのルートへアクセスされると自動的に認証が求められます。デフォルトでは、auth.basic
ミドルウェアはユーザを決める”username”としてユーザのemail
カラムを使用します。
FastCGIの注意
PHP FastCGIを使用している場合、初期状態のままでHTTP基本認証は正しく動作しないでしょう。以下の行を.htaccess
ファイルへ追加してください。
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
ステートレスなHTTP基本認証
セッションの識別クッキーを用いずにHTTP基本認証を使用することもできます。これは特にAPI認証に便利です。実装するには、onceBasic
メソッドを呼び出すミドルウェアを定義してください。onceBasic
メソッドが何もレスポンスを返さなかった場合、リクエストをアプリケーションの先の処理へ通します。
<?php
namespace Illuminate\Auth\Middleware;
use Illuminate\Support\Facades\Auth;
class AuthenticateOnceWithBasicAuth
{
/**
* 送信されたリクエストの処理
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, $next)
{
return Auth::onceBasic() ?: $next($request);
}
}
次にルートミドルウェアを登録し、ルートに付加します。
Route::get('api/user', function() {
// 認証済みのユーザのみが入れる
})->middleware('auth.basic.once');
カスタムガードの追加
独自の認証ガードはAuth
ファサードのextend
メソッドを使用し、定義します。サービスプロバイダの中で呼び出します。AuthServiceProvider
をLaravelは予め用意しているので、この中にコードを設置できます。
<?php
namespace App\Providers;
use App\Services\Auth\JwtGuard;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* サービスの初期起動後の登録実行
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::extend('jwt', function($app, $name, array $config) {
// Illuminate\Contracts\Auth\Guardのインスタンスを返す
return new JwtGuard(Auth::createUserProvider($config['provider']));
});
}
}
上記の例のように、コールバックをextend
メソッドに渡し、Illuminate\Contracts\Auth\Guard
の実装を返します。このインスタンスは、カスタムガードで定義が必要ないくつかのメソッドを持っています。カスタムガードが定義できたら、auth.php
設定ファイルの、guards
設定で使用できます。
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
カスタムユーザプロバイダの追加
ユーザ情報を保管するために伝統的なリレーショナルデータベースを使用したくなければ、Laravelに独自の認証ユーザプロバイダを拡張する必要があります。Auth
ファサードのprovider
メソッドを使い、カスタムユーザプロバイダを定義します。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Auth;
use App\Extensions\RiakUserProvider;
use Illuminate\Support\ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* サービスの初期起動後の登録実行
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::provider('riak', function($app, array $config) {
// Illuminate\Contracts\Auth\UserProviderのインスタンスを返す
return new RiakUserProvider($app->make('riak.connection'));
});
}
}
provider
メソッドでプロバイダを登録したら、auth.php
設定ファイルで新しいユーザプロバイダへ切り替えます。最初に、新しいドライバを使用するprovider
を定義します。
'providers' => [
'users' => [
'driver' => 'riak',
],
],
次に、このプロバイダをguards
設定項目で利用します。
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
ユーザプロバイダ契約
Illuminate\Contracts\Auth\UserProvider
は、MySQLやRiakなどのような持続性のストレージシステムに対するIlluminate\Contracts\Auth\Authenticatable
の実装を取得することだけに責任を持っています。これらの2つのインターフェイスはユーザデータがどのように保存されているか、それを表すのがどんなタイプのクラスなのかに関わらず、認証メカニズムを機能し続けるために役立っています。
Illuminate\Contracts\Auth\UserProvider
契約を見てみましょう。
<?php
namespace Illuminate\Contracts\Auth;
interface UserProvider {
public function retrieveById($identifier);
public function retrieveByToken($identifier, $token);
public function updateRememberToken(Authenticatable $user, $token);
public function retrieveByCredentials(array $credentials);
public function validateCredentials(Authenticatable $user, array $credentials);
}
retrieveById
関数は通常MySQLデータベースの自動増分IDのようなユーザを表すキーを受け付けます。IDにマッチするAuthenticatable
実装が取得され、返されます。
retrieveByToken
関数は一意の$identifier
とremember_token
フィールドに保存されている”remember me” $token
からユーザを取得します。前のメソッドと同じく、Authenticatable
実装が返されます。
updateRememberToken
メソッドは$user
のremember_token
フィールドを新しい$token
で更新します。新しいトークンは真新しいものでも、「Remember me」ログインに成功した時の値でも、ログアウト時のnull
値でも受け付けます。
retrieveByCredentials
メソッドはアプリケーションへログイン時にAuth::attempt
メソッドに指定するのと同じく、ユーザ認証情報の配列を引数に取ります。メソッドは認証情報に一致するユーザを裏の持続ストレージから「クエリ」する必要があります。典型的な使用方法の場合、このメソッドは$credentials['username']
の”where”条件でクエリを実行するでしょう。メソッドはAuthenticatable
の実装を返します。このメソッドはパスワードバリデーションや認証を行ってはいけません
validateCredentials
メソッドは指定された$user
とユーザを認証するための$credentials
とを比較します。たとえばこのメソッドは$user->getAuthPassword()
の値と$credentials['password']
をHash::make
で値を比較します。このメソッドはパスワードが有効であるかを示す、true
かfalse
だけを返します。
Authenticatable契約
これでUserProvider
の各メソッドが明らかになりました。続いてAuthenticatable
契約を見てみましょう。プロバイダはretrieveById
とretrieveByCredentials
メソッドでこのインターフェイスの実装を返していたことを思い出してください。
<?php
namespace Illuminate\Contracts\Auth;
interface Authenticatable {
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPassword();
public function getRememberToken();
public function setRememberToken($value);
public function getRememberTokenName();
}
このインターフェイスはシンプルです。getAuthIdentifierName
メソッドは、ユーザの「主キー」フィールドの名前を返します。getAuthIdentifier
メソッドはユーザの主キーを返します。MySQLを裏で使用している場合、これは自動増分される主キーでしょう。getAuthPassword
はユーザのハッシュ済みのパスワードを返します。このインターフェイスはどのORMや抽象ストレージ層を使用しているかに関わらず、どんなUserクラスに対しても認証システムが動作するようにしてくれています。デフォルトでLaravelはapp
ディレクトリ中に、このインターフェイスを実装してるUser
クラスを持っています。ですから実装例として、このクラスを調べてみてください。
イベント
Laravelは認証処理の過程で、様々なイベントを発行します。EventServiceProvider
の中で、こうしたイベントに対するリスナを設定できます。:
/**
* アプリケーションに指定されたイベントリスナ
*
* @var array
*/
protected $listen = [
'Illuminate\Auth\Events\Registered' => [
'App\Listeners\LogRegisteredUser',
],
'Illuminate\Auth\Events\Attempting' => [
'App\Listeners\LogAuthenticationAttempt',
],
'Illuminate\Auth\Events\Registered' => [
'App\Listeners\LogRegisteredUser',
],
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
'Illuminate\Auth\Events\Logout' => [
'App\Listeners\LogSuccessfulLogout',
],
'Illuminate\Auth\Events\Lockout' => [
'App\Listeners\LogLockout',
],
];
コメント