Skip to content

安全

配置

Laravel旨在使实现认证变得非常简单。实际上,几乎所有内容都是开箱即用的。认证配置文件位于app/config/auth.php,其中包含多个文档良好的选项,用于调整认证功能的行为。

默认情况下,Laravel在你的app/models目录中包含一个User模型,可以与默认的Eloquent认证驱动一起使用。请记住,在为此模型构建Schema时,确保密码字段至少为60个字符。

如果你的应用程序不使用Eloquent,你可以使用database认证驱动,该驱动使用Laravel查询构建器。

lightbulb

在开始之前,请确保你的users(或等效)表包含一个可空的、字符串类型的remember_token列,长度为100个字符。此列将用于存储由你的应用程序维护的“记住我”会话的令牌。这可以通过在迁移中使用$table->rememberToken();来完成。

存储密码

Laravel的Hash类提供安全的Bcrypt哈希:

使用Bcrypt哈希密码

php
$password = Hash::make('secret');

验证密码与哈希值

php
if (Hash::check('secret', $hashedPassword))
{
	// 密码匹配...
}

检查密码是否需要重新哈希

php
if (Hash::needsRehash($hashed))
{
	$hashed = Hash::make('secret');
}

用户认证

要将用户登录到你的应用程序中,你可以使用Auth::attempt方法。

php
if (Auth::attempt(array('email' => $email, 'password' => $password)))
{
	return Redirect::intended('dashboard');
}

请注意,email不是必需的选项,它仅用于示例。你应该使用与你的数据库中“用户名”对应的任何列名。Redirect::intended函数将把用户重定向到他们在被认证过滤器捕获之前试图访问的URL。如果意图的目标不可用,可以在此方法中给出一个后备URI。

当调用attempt方法时,将触发auth.attempt 事件。如果认证尝试成功并且用户已登录,则还会触发auth.login事件。

确定用户是否已认证

要确定用户是否已经登录到你的应用程序中,你可以使用check方法:

php
if (Auth::check())
{
	// 用户已登录...
}

认证用户并“记住”他们

如果你希望在应用程序中提供“记住我”功能,可以将true作为第二个参数传递给attempt方法,这将使用户无限期保持认证状态(或直到他们手动注销)。当然,你的users表必须包含字符串类型的remember_token列,该列将用于存储“记住我”令牌。

php
if (Auth::attempt(array('email' => $email, 'password' => $password), true))
{
	// 用户被记住...
}

Note: 如果attempt方法返回true,则用户被视为已登录到应用程序中。

确定用户是否通过记住功能认证

如果你正在“记住”用户登录,你可以使用viaRemember方法来确定用户是否通过“记住我”cookie进行了认证:

php
if (Auth::viaRemember())
{
	//
}

带条件的用户认证

你还可以向认证查询添加额外条件:

php
if (Auth::attempt(array('email' => $email, 'password' => $password, 'active' => 1)))
{
    // 用户是活跃的,没有被暂停,并且存在。
}
lightbulb

为了增加对会话固定攻击的保护,用户的会话ID将在认证后自动重新生成。

访问已登录用户

一旦用户被认证,你可以访问用户模型/记录:

php
$email = Auth::user()->email;

要检索已认证用户的ID,可以使用id方法:

php
$id = Auth::id();

要通过用户ID简单地将用户登录到应用程序中,请使用loginUsingId方法:

php
Auth::loginUsingId(1);

无需登录验证用户凭据

validate方法允许你验证用户的凭据,而不实际将他们登录到应用程序中:

php
if (Auth::validate($credentials))
{
	//
}

单次请求登录用户

你还可以使用once方法将用户登录到应用程序中,仅限于单次请求。不会使用会话或cookie。

php
if (Auth::once($credentials))
{
	//
}

将用户登出应用程序

php
Auth::logout();

手动登录用户

如果你需要将现有用户实例登录到你的应用程序中,你可以简单地调用login方法并传入实例:

php
$user = User::find(1);

Auth::login($user);

这等同于通过凭据使用attempt方法登录用户。

保护路由

路由过滤器可用于仅允许经过认证的用户访问特定路由。Laravel默认提供auth过滤器,并在app/filters.php中定义。

保护路由

php
Route::get('profile', array('before' => 'auth', function()
{
	// 只有经过认证的用户才能进入...
}));

CSRF保护

Laravel提供了一种简单的方法来保护你的应用程序免受跨站请求伪造攻击。

在表单中插入CSRF令牌

php
<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">

验证提交的CSRF令牌

php
Route::post('register', array('before' => 'csrf', function()
{
    return '你提供了有效的CSRF令牌!';
}));

HTTP基本认证

HTTP基本认证提供了一种快速的方法来认证你的应用程序用户,而无需设置专门的“登录”页面。要开始,向你的路由附加auth.basic过滤器:

使用HTTP基本保护路由

php
Route::get('profile', array('before' => 'auth.basic', function()
{
	// 只有经过认证的用户才能进入...
}));

默认情况下,basic过滤器将在认证时使用用户记录中的email列。如果你希望使用其他列,可以在app/filters.php文件中将列名作为第一个参数传递给basic方法:

php
Route::filter('auth.basic', function()
{
	return Auth::basic('username');
});

设置无状态HTTP基本过滤器

你还可以在不设置用户标识符cookie的情况下使用HTTP基本认证,这对于API认证特别有用。为此,定义一个返回onceBasic方法的过滤器:

php
Route::filter('basic.once', function()
{
	return Auth::onceBasic();
});

如果你使用PHP FastCGI,HTTP基本认证默认情况下将无法正常工作。以下行应添加到你的.htaccess文件中:

php
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

密码提醒与重置

模型与表

大多数Web应用程序提供一种方法,让用户重置他们忘记的密码。Laravel提供方便的方法来发送密码提醒和执行密码重置,而不是强迫你在每个应用程序中重新实现这一点。要开始,验证你的User模型是否实现了Illuminate\Auth\Reminders\RemindableInterface接口。当然,框架中包含的User模型已经实现了此接口,并使用Illuminate\Auth\Reminders\RemindableTrait来包含实现该接口所需的方法。

实现RemindableInterface

php
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;

class User extends Eloquent implements RemindableInterface {

	use RemindableTrait;

}

生成提醒表迁移

接下来,必须创建一个表来存储密码重置令牌。要生成此表的迁移,只需执行auth:reminders-table Artisan命令:

php
php artisan auth:reminders-table

php artisan migrate

密码提醒控制器

现在我们准备生成密码提醒控制器。要自动生成控制器,你可以使用auth:reminders-controller Artisan命令,这将在你的app/controllers目录中创建一个RemindersController.php文件。

php
php artisan auth:reminders-controller

生成的控制器将已经有一个getRemind方法,该方法处理显示你的密码提醒表单。你只需通过在app/views/password/目录中创建一个文件remind.blade.php来创建一个基本的password.remind 模板。 此视图应具有一个带有email字段的基本表单。该表单应POST到RemindersController@postRemind操作。

password.remind视图上的简单表单可能如下所示:

php
<form action="{{ action('RemindersController@postRemind') }}" method="POST">
	<input type="email" name="email">
	<input type="submit" value="发送提醒">
</form>

除了getRemind,生成的控制器还将已经有一个postRemind方法,该方法处理向用户发送密码提醒电子邮件。如果成功向用户发送提醒电子邮件,则会将status消息闪烁到会话中。如果提醒失败,则会闪烁一个error消息。

postRemind控制器方法中,你可以在发送给用户之前修改消息实例:

php
Password::remind(Input::only('email'), function($message)
{
	$message->subject('密码提醒');
});

你的用户将收到一封电子邮件,其中包含指向控制器的getReset方法的链接。密码提醒令牌将用于标识给定的密码提醒尝试,并将传递给控制器方法。该操作已配置为返回一个password.reset模板,你应该构建该模板。token将被传递到视图中,你应该将此令牌放在名为token的隐藏表单字段中。除了token,你的密码重置表单还应包含emailpasswordpassword_confirmation字段。该表单应POST到RemindersController@postReset方法。

password.reset视图上的简单表单可能如下所示:

php
<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方法自定义这些规则,该方法接受一个闭包。在此闭包中,你可以进行任何密码验证。请注意,你不需要验证密码是否匹配,因为这将由框架自动完成。

php
Password::validator(function($credentials)
{
	return strlen($credentials['password']) >= 6;
});
lightbulb

默认情况下,密码重置令牌在一小时后过期。你可以通过app/config/auth.php文件中的reminder.expire选项更改此设置。

加密

Laravel提供强大的AES加密功能,使用mcrypt PHP扩展:

加密一个值

php
$encrypted = Crypt::encrypt('secret');
lightbulb

确保在app/config/app.php文件的key选项中设置一个16、24或32个字符的随机字符串。否则,加密值将不安全。

解密一个值

php
$decrypted = Crypt::decrypt($encryptedValue);

设置密码和模式

你还可以设置加密器使用的密码和模式:

php
Crypt::setMode('ctr');

Crypt::setCipher($cipher);

认证驱动

Laravel提供databaseeloquent认证驱动。有关添加其他认证驱动的更多信息,请查看认证扩展文档.