安全性
設置
Laravel 目標是讓實作身分驗證變得非常容易,事實上,大部分的驗證設定都已經設定好了,驗證設定檔放在 app/config/auth.php
,設定檔中有可以調整驗證行為的選項。
Laravel 預設包含 User
模型,該模型檔案放在 app/models
目錄中,而模型預設使用 Eloquent 來做驗證驅動,請記得在建立 User
模型的資料表時,password 的欄位至少要 60 個字元。
如果你的應用程式沒有使用 Eloquent,你也可以使用 database
驗證驅動,該驅動會使用 Laravel 查詢建立器來做驗證查詢。
儲存密碼
Laravel Hash
類別提供一個安全的 Bcrypt 雜湊(hashing):
使用 Bcrypt 做密碼雜湊
$password = Hash::make('secret');
驗證雜湊密碼
if (Hash::check('secret', $hashedPassword))
{
// 密碼符合...
}
檢查密碼是否需要重新雜湊
if (Hash::needsRehash($hashed))
{
$hashed = Hash::make('secret');
}
驗證使用者
你可以使用 Auth::attempt
方法讓使用者登入你的應用程式。
if (Auth::attempt(array('email' => $email, 'password' => $password)))
{
return Redirect::intended('dashboard');
}
注意 email
不是驗證必須要的選項,這裡僅僅是做範例使用,你可以使用任何資料表的欄位名稱當作 "帳號名稱(username)" , Redirect::intended
方法會將使用者重新導向至被驗證過濾器捕捉前,使用者原先試著存取的網址,也可以給這個方法一個 URI,當無法重新導回使用者原先試著存取的網址時,則會導向至你指定的 URI。
當 attempt
方法被呼叫,auth.attempt
事件 將會被觸發,加入驗證成功時 auth.login
事件也會被觸發。
你可以使用 check
方法去判斷使用者是否已經登入到你的應用程式:
判斷使用者是否被驗證
if (Auth::check())
{
// 使用者已登入...
}
假如你想要提供 "記住我" 的功能,你可以在 attempt
方法第二個參數傳送 true
,這樣將會永遠保持使用者為驗證登入狀態 (直到使用者手動登入):
驗證使用者並"記住"他們
if (Auth::attempt(array('email' => $email, 'password' => $password), true))
{
// 使用者驗證資訊被記住...
}
注意: 假如 attempt
方法回傳 true
時,表示使用者已經成功登入應用程式了
你可能想加入額外的條件到驗證查詢中:
加入驗證使用者條件
if (Auth::attempt(array('email' => $email, 'password' => $password, 'active' => 1)))
{
// 使用者帳號啟動中,沒被停權,並且帳號存在
}
只要使用者被驗證後,你就可以存取 User 模型/紀錄:
存取登入使用者資料
$email = Auth::user()->email;
可以使用loginUsingId
方法,簡單的使用使用者的編號 (ID) 登入應用程式:
Auth::loginUsingId(1);
validate
方法允許你僅僅驗證使用者身分,而不登入應用程式:
驗證使用者身分而不登入
if (Auth::validate($credentials))
{
//
}
你也可以使用 once
方法,在這個請求中登入應用程式一次,而登入資訊不會放到 session 或 cookies 中。
在單一請求中登入驗證使用者
if (Auth::once($credentials))
{
//
}
登出應用程式
Auth::logout();
手動
如果你想要登入一個已經存在於應用程式的使用者帳戶,你只要呼叫 login
方法,並傳送使用者的資料進去即可:
$user = User::find(1);
Auth::login($user);
這個方法相當於使用 attempt
方法登入使用者帳戶。
保護路由
路由過濾器可以允許只有驗證個使用者可以存取這個路由,Laravel 預設提供 auth
過濾器,而這個過濾器被定義在 app/filters.php
檔案中。
保護路由
Route::get('profile', array('before' => 'auth', function()
{
// 只有驗證過的使用者可以進入...
}));
CSRF 保護
Laravel 提供一個簡單的方法保護你的應用程式不會受到跨網站偽造請求的攻擊(CSRF:cross-site request forgeries)
插入 CSRF 標記到表單中
<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
驗證傳送的 CSRF 標記
Route::post('register', array('before' => 'csrf', function()
{
return '你給了一個合法的 CSRF 標記!';
}));
HTTP基本驗證
HTTP 基本驗證提供一個快速的方法去驗證使用者身分,而不用設定一個專用的 "登入" 頁面,在開始時,附加一個 auth.basic
過濾器到你的路由中:
使用HTTP基本驗證保護路由
Route::get('profile', array('before' => 'auth.basic', function()
{
// 只有驗證過的使用者可以進入...
}));
basic
過濾器在預設情況下會使用 email
欄位資料去記錄使用者的驗證狀態,假如你希望使用其他的欄位,你可以傳遞欄位名稱到 basic
方法中:
return Auth::basic('username');
你也可以使用HTTP基本驗證時,不將使用者登入資訊記錄到 session 中,在做 API 驗證時特別有用,為了達到這樣的目的,訂一個過濾器回傳 onceBasic
方法的資料。
設定無狀態的HTTP基本過濾器
Route::filter('basic.once', function()
{
return Auth::onceBasic();
});
密碼提醒及重設
傳送密碼提醒
大部分的應用程式提供方法讓使用者重設他們忘記的密碼,與其強迫你在每個應用程式重新實作這個功能,Laravel 提供一個非常方便方法去傳送密碼提示及做密碼重設,在開始前,確認你的 User
模型有時實作 Illuminate\Auth\Reminders\RemindableInterface
介面的功能,,當然包含在 Laravel 中的 User
模型已經實作了這個介面。
實作 RemindableInterface 介面
class User extends Eloquent implements RemindableInterface {
public function getReminderEmail()
{
return $this->email;
}
}
接下來,必須建立資料表去儲存密碼重設標記 (token),只要在 Artisan 執行 auth:reminders
就可以 migration 這個資料表:
產生忘記密碼資料表 Migration
php artisan auth:reminders
php artisan migrate
我們可以使用 Password::remind
方法去傳送密碼重設提示:
傳送密碼重設提示
Route::post('password/remind', function()
{
$credentials = array('email' => Input::get('email'));
return Password::remind($credentials);
});
注意,傳送到 remind
方法的參數與傳送到 Auth::attempt
的方法類似,這個方法將會取得 User
模型的資料,並透過 E-mail 傳送一個密碼重設連結給使用者,Email 視圖將會傳送一個到重設密碼頁的連結,並帶著 token
變數在這個連結上, user
物件資訊也會傳送到視圖上。
注意: 你也可以透過
auth.reminder.email
選項,去自訂重設密碼郵件的視圖,當然已經有提供預設的視圖了
你也可以透過傳送給 remind
第二個參數,去變更發送給使用者郵件的內容:
return Password::remind($credentials, function($message, $user)
{
$message->subject('Your Password Reminder');
});
你可能會注意到我們直接回傳 remind
的結果給路由,在預設情況下, remind
方法將會傳送一個重導 (Redirect)
到目前網址的 URI,假如嘗試重設密碼時發生錯誤, error
變數將會寫到 session 中,還有一個原因的 reason
變數會被從 reminders
語言檔中取得,假如密碼重設成功,則 success
變數將會寫到 session 中,所以你的密碼重設表單看起來會像這樣:
@if (Session::has('error'))
{{ trans(Session::get('reason')) }}
@elseif (Session::has('success'))
An e-mail with the password reset has been sent.
@endif
<input type="text" name="email">
<input type="submit" value="Send Reminder">
重設密碼
只要使用者點擊了重設密碼提示郵件中的重設密碼連結,則會被導向到一個有 token
欄位的表單,以及 password
及 password_confirmation
欄位,以下是一個路由至密碼重設表單的範例:
Route::get('password/reset/{token}', function($token)
{
return View::make('auth.reset')->with('token', $token);
});
密碼重設表單看起來會像:
@if (Session::has('error'))
{{ trans(Session::get('reason')) }}
@endif
<input type="hidden" name="token" value="{{ $token }}">
<input type="text" name="email">
<input type="password" name="password">
<input type="password" name="password_confirmation">
再次強調,我們在重設密碼偵錯到錯誤時,會使用 Session
去顯示所有的錯誤,,接下來,我們可以定義一個 POST
路由來處理重設密碼:
Route::post('password/reset/{token}', function()
{
$credentials = array('email' => Input::get('email'));
return Password::reset($credentials, function($user, $password)
{
$user->password = Hash::make($password);
$user->save();
return Redirect::to('home');
});
});
如果密碼重設成功, User
實例及密碼將會傳送到你的閉合函式中,允許你真的去執行儲存新密碼的操作,接下來你可以在 reset
方法中回傳 Redirect
轉址或者任何其他類型的回應,這邊要注意到,reset
方法將會自動檢查在這個請求的 標記 (token)
及驗證是否合法,以及密碼與確認密碼是否符合。
與 remind
方法類似的地方是,假如重設密碼時發生錯誤十, reset
方法將會傳送 error
及 reason
兩個變數資料,並 重導 (Redirect)
到目前的 URI。
加密
Laravel 透過 PHP 的 mcrypt 延伸套件,提供了強大的 AES-256 加密方法:
加密
$encrypted = Crypt::encrypt('secret');
注意: 必須要確認在
app/config/app.php
檔案中,有設定一個長度為 32 的亂數字串到key
選項中,否則加密值會很不安全。
解密
$decrypted = Crypt::decrypt($encryptedValue);
你也可以設定加密器的 密碼(cipher) 及 模式(mode):
設定密碼(cipher) 及 模式(mode)
Crypt::setMode('crt');
Crypt::setCipher($cipher);