安全
配置
Laravel旨在使实现认证变得非常简单。实际上,几乎所有内容都是开箱即用的。认证配置文件位于app/config/auth.php
,其中包含多个文档良好的选项,用于调整认证功能的行为。
默认情况下,Laravel在你的app/models
目录中包含一个User
模型,可以与默认的Eloquent认证驱动一起使用。请记住,在为此模型构建Schema时,确保密码字段至少为60个字符。
如果你的应用程序不使用Eloquent,你可以使用database
认证驱动,该驱动使用Laravel查询构建器。
在开始之前,请确保你的users
(或等效)表包含一个可空的、字符串类型的remember_token
列,长度为100个字符。此列将用于存储由你的应用程序维护的“记住我”会话的令牌。这可以通过在迁移中使用$table->rememberToken();
来完成。
存储密码
Laravel的Hash
类提供安全的Bcrypt哈希:
使用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
不是必需的选项,它仅用于示例。你应该使用与你的数据库中“用户名”对应的任何列名。Redirect::intended
函数将把用户重定向到他们在被认证过滤器捕获之前试图访问的URL。如果意图的目标不可用,可以在此方法中给出一个后备URI。
当调用attempt
方法时,将触发auth.attempt
事件。如果认证尝试成功并且用户已登录,则还会触发auth.login
事件。
确定用户是否已认证
要确定用户是否已经登录到你的应用程序中,你可以使用check
方法:
if (Auth::check())
{
// 用户已登录...
}
认证用户并“记住”他们
如果你希望在应用程序中提供“记住我”功能,可以将true
作为第二个参数传递给attempt
方法,这将使用户无限期保持认证状态(或直到他们手动注销)。当然,你的users
表必须包含字符串类型的remember_token
列,该列将用于存储“记住我”令牌。
if (Auth::attempt(array('email' => $email, 'password' => $password), true))
{
// 用户被记住...
}
Note: 如果attempt
方法返回true
,则用户被视为已登录到应用程序中。
确定用户是否通过记住功能认证
如果你正在“记住”用户登录,你可以使用viaRemember
方法来确定用户是否通过“记住我”cookie进行了认证:
if (Auth::viaRemember())
{
//
}
带条件的用户认证
你还可以向认证查询添加额外条件:
if (Auth::attempt(array('email' => $email, 'password' => $password, 'active' => 1)))
{
// 用户是活跃的,没有被暂停,并且存在。
}
为了增加对会话固定攻击的保护,用户的会话ID将在认证后自动重新生成。
访问已登录用户
一旦用户被认证,你可以访问用户模型/记录:
$email = Auth::user()->email;
要检索已认证用户的ID,可以使用id
方法:
$id = Auth::id();
要通过用户ID简单地将用户登录到应用程序中,请使用loginUsingId
方法:
Auth::loginUsingId(1);
无需登录验证用户凭据
validate
方法允许你验证用户的凭据,而不实际将他们登录到应用程序中:
if (Auth::validate($credentials))
{
//
}
单次请求登录用户
你还可以使用once
方法将用户登录到应用程序中,仅限于单次请求。不会使用会话或cookie。
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令牌
<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
列。如果你希望使用其他列,可以在app/filters.php
文件中将列名作为第一个参数传递给basic
方法:
Route::filter('auth.basic', function()
{
return Auth::basic('username');
});
设置无状态HTTP基本过滤器
你还可以在不设置用户标识符cookie的情况下使用HTTP基本认证,这对于API认证特别有用。为此,定义一个返回onceBasic
方法的过滤器:
Route::filter('basic.once', function()
{
return Auth::onceBasic();
});
如果你使用PHP FastCGI,HTTP基本认证默认情况下将无法正常工作。以下行应添加到你的.htaccess
文件中:
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
密码提醒与重置
模型与表
大多数Web应用程序提供一种方法,让用户重置他们忘记的密码。Laravel提供方便的方法来发送密码提醒和执行密码重置,而不是强迫你在每个应用程序中重新实现这一点。要开始,验证你的User
模型是否实现了Illuminate\Auth\Reminders\RemindableInterface
接口。当然,框架中包含的User
模型已经实现了此接口,并使用Illuminate\Auth\Reminders\RemindableTrait
来包含实现该接口所需的方法。
实现RemindableInterface
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements RemindableInterface {
use RemindableTrait;
}
生成提醒表迁移
接下来,必须创建一个表来存储密码重置令牌。要生成此表的迁移,只需执行auth:reminders-table
Artisan命令:
php artisan auth:reminders-table
php artisan migrate
密码提醒控制器
现在我们准备生成密码提醒控制器。要自动生成控制器,你可以使用auth:reminders-controller
Artisan命令,这将在你的app/controllers
目录中创建一个RemindersController.php
文件。
php artisan auth:reminders-controller
生成的控制器将已经有一个getRemind
方法,该方法处理显示你的密码提醒表单。你只需通过在app/views/password/
目录中创建一个文件remind.blade.php
来创建一个基本的password.remind
模板。 此视图应具有一个带有email
字段的基本表单。该表单应POST到RemindersController@postRemind
操作。
password.remind
视图上的简单表单可能如下所示:
<form action="{{ action('RemindersController@postRemind') }}" method="POST">
<input type="email" name="email">
<input type="submit" value="发送提醒">
</form>
除了getRemind
,生成的控制器还将已经有一个postRemind
方法,该方法处理向用户发送密码提醒电子邮件。如果成功向用户发送提醒电子邮件,则会将status
消息闪烁到会话中。如果提醒失败,则会闪烁一个error
消息。
在postRemind
控制器方法中,你可以在发送给用户之前修改消息实例:
Password::remind(Input::only('email'), function($message)
{
$message->subject('密码提醒');
});
你的用户将收到一封电子邮件,其中包含指向控制器的getReset
方法的链接。密码提醒令牌将用于标识给定的密码提醒尝试,并将传递给控制器方法。该操作已配置为返回一个password.reset
模板,你应该构建该模板。token
将被传递到视图中,你应该将此令牌放在名为token
的隐藏表单字段中。除了token
,你的密码重置表单还应包含email
、password
和password_confirmation
字段。该表单应POST到RemindersController@postReset
方法。
password.reset
视图上的简单表单可能如下所示:
<form action="{{ action('RemindersController@postReset') }}" method="POST">
<input type="hidden" name="token" value="{{ $token }}">
<input type="email" name="email">
<input type="password" name="password">
<input type="password" name="password_confirmation">
<input type="submit" value="重置密码">
</form>
最后,postReset
方法负责实际更改存储中的密码。在此控制器操作中,传递给Password::reset
方法的闭包设置User
上的password
属性并调用save
方法。当然,此闭包假设你的User
模型是一个Eloquent模型;但是,你可以根据需要更改此闭包,以使其与应用程序的数据库存储系统兼容。
如果密码成功重置,用户将被重定向到应用程序的根目录。再次强调,你可以更改此重定向URL。如果密码重置失败,用户将被重定向回重置表单,并且会闪烁一个error
消息到会话中。
密码验证
默认情况下,Password::reset
方法将验证密码是否匹配并且长度>=六个字符。你可以使用Password::validator
方法自定义这些规则,该方法接受一个闭包。在此闭包中,你可以进行任何密码验证。请注意,你不需要验证密码是否匹配,因为这将由框架自动完成。
Password::validator(function($credentials)
{
return strlen($credentials['password']) >= 6;
});
默认情况下,密码重置令牌在一小时后过期。你可以通过app/config/auth.php
文件中的reminder.expire
选项更改此设置。
加密
Laravel提供强大的AES加密功能,使用mcrypt PHP扩展:
加密一个值
$encrypted = Crypt::encrypt('secret');
确保在app/config/app.php
文件的key
选项中设置一个16、24或32个字符的随机字符串。否则,加密值将不安全。
解密一个值
$decrypted = Crypt::decrypt($encryptedValue);
设置密码和模式
你还可以设置加密器使用的密码和模式:
Crypt::setMode('ctr');
Crypt::setCipher($cipher);
认证驱动
Laravel提供database
和eloquent
认证驱动。有关添加其他认证驱动的更多信息,请查看认证扩展文档.