用户认证
简介
想要快速起步? 在一个全新的 Laravel 应用中运行 php artisan make:auth
命令,然后可以用浏览器访问 http://your-app.dev/register
或者你在程序中定义的其他 url。这个简单的命令就可以搭建好整个认证系统的脚手架。
Laravel 中实现用户认证非常简单。实际上,几乎所有东西都已经为你配置好了。配置文件位于 config/auth.php
,其中包含了用于调整认证服务行为的、标注好注释的选项配置。
在其核心代码中,Laravel 的认证组件由 guards
和 providers
组成,Guard 定义了用户在每个请求中如何实现认证,例如,Laravel 通过 session
guard 来维护 Session 存储的状态和 Cookie。
Provider 定义了如何从持久化存储中获取用户信息,Laravel 底层支持通过 Eloquent 和数据库查询构建器两种方式来获取用户,如果需要的话,你还可以定义额外的 Provider。
如果看到这些名词觉得很困惑,大可不必太过担心,因为对绝大多数应用而言,只需使用默认认证配置即可,不需要做什么改动。
数据库注意事项
默认的 Laravel 在 app
文件夹中会含有 App\User
Eloquent 模型。这个模型将使用默认的 Eloquent 认证来驱动。如果你的应用程序没有使用 Eloquent,请选择使用 Laravel 查询构造器的 database
认证驱动。
为 App\User
模型创建数据库表结构时,确认密码字段最少必须 60 字符长。保持字段原定的 255 字符长是个好选择。
users
数据表中必须含有 nullable 、100 字符长的 remember_token
字段。当用户登录应用并勾选「记住我」时,这个字段将会被用来保存「记住我」 session 的令牌。
认证快速入门
Laravel 带有两个认证控制器,它们被放置在 App\Http\Controllers\Auth
命名空间内,RegisterController
处理用户注册,LoginController
处理用户认证,ForgotPasswordController
处理重置密码的 e-mail 链接,ResetPasswordController
包含重置密码的逻辑。
这些控制器使用了 trait 来包含所需要的方法,对于大多数的应用程序而言,你并不需要修改这些控制器。
路由
Laravel 通过运行如下命令可快速生成认证所需要的路由和视图:
php artisan make:auth
该命令应该在新安装的应用下使用,它会生成 layout 布局视图,注册和登录视图,以及所有的认证路由,同时生成 HomeController
,用来处理登录成功后会跳转到该控制器下的请求。
视图
正如上面所提到的,php artisan make:auth
命令会在 resources/views/auth
目录下创建所有认证需要的视图。
make:auth
命令还创建了 resources/views/layouts
目录,该目录下包含了应用的基础布局文件。所有这些视图都基于 Bootstrap CSS 框架,你也可以根据需要对其进行自定义。
认证
现在你已经为自带的认证控制器设置好了路由和视图,接下来我们来实现新用户注册和登录认证。你可以在浏览器中访问定义好的路由,认证控制器已经(通过 trait)包含了注册及登录逻辑。
自定义路径
当一个用户成功进行登录认证后,默认将会跳转到 /home
,你可以通过在 LoginController
,RegisterController
和 ResetPasswordController
中设置 redirectTo
属性来自定义登录认证成功之后的跳转路径:
protected $redirectTo = '/';
当一个用户登录认证失败后,默认将会自动跳转回登录表单对应的页面。
自定义用户名
Laravel默认使用 email
字段来认证。如果你想用其他字段认证,可以在 LoginController
里面定义一个 username
方法
public function username()
{
return 'username';
}
自定义 Guard
你还可以自定义实现用户认证的 「guard」,要实现这一功能,需要在 LoginController
,RegisterController
和 ResetPasswordController
中定义 guard
方法,该方法需要返回一个 guard 实例:
use Illuminate\Support\Facades\Auth;
protected function guard()
{
return Auth::guard('guard-name');
}
自定义验证 / 存储
要修改新用户注册所必需的表单字段,或者自定义新用户字段如何存储到数据库,你可以修改 RegisterController
类。该类负责为应用验证输入参数和创建新用户。
RegisterController
的 validator
方法包含了新用户的验证规则,你可以按需要自定义该方法。
RegisterController
的 create
方法负责使用 Eloquent ORM 在数据库中创建新的 App\User
记录。当然,你也可以基于自己的需求自定义该方法。
获取已认证的用户信息
可以通过 Auth
facade 来访问认证的用户。
use Illuminate\Support\Facades\Auth;
// 获取当前已通过认证的用户...
$user = Auth::user();
// 获取当前已通过认证的用户id...
$id = Auth::id();
也有另外一种方法可以访问认证过的用户,就是通过 Illuminate\Http\Request
实例,请注意类型提示的类会被自动注入:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
/**
* Update the user's profile.
*
* @param Request $request
* @return Response
*/
public function update(Request $request)
{
if ($request->user()) {
// $request->user() 返回认证过的用户的实例...
}
}
}
检查用户是否登录
使用 Auth
facade 的 check
方法来检查用户是否登录,如果已经登录,将会返回 true
:
use Illuminate\Support\Facades\Auth;
if (Auth::check()) {
// 这个用户已经登录...
}
尽管可以使用 check
方法来检查用户是否登录,在允许该用户访问特定的路由或控制器之前,可以使用中间件来检查用户是否认证过。要想得到更多信息,请阅读 限制路由访问 的文档。
限制路由访问
路由中间件 用于限定认证过的用户访问指定的路由,Laravel 提供了 auth
中间件来达到这个目的,而这个中间件被定义在 app\Http\Middleware\Authenticate.php
中。因为这个中间件已经在 HTTP kernel 中注册了,只需要将它应用到路由定义中即可使用:
Route::get('profile', ['middleware' => 'auth', function() {
// 只有认证过的用户能进来这里...
}]);
如果使用 控制器类,可以在构造器中调用 middleware
方法,来代替在路由中直接定义:
public function __construct()
{
$this->middleware('auth');
}
指定一个Guard
添加 auth
中间件到路由后,还需要指定使用哪个 guard 来实现认证。指定的 guard 对应配置文件 auth.php
中 guards
数组的某个键:
public function __construct()
{
$this->middleware('auth:api');
}
登录限流
Laravel 内置的 LoginController
类提供 Illuminate\Foundation\Auth\ThrottlesLogins
trait 允许你在应用程序中限制登录次数。默认情况下,如果用户在进行几次尝试后仍不能提供正确的凭证,将在一分 钟内无法进行登录。这个限制会特别针对用户的用户名称 / 邮件地址和他们的 IP 地址。
手动认证用户
当然,不一定要使用 Laravel 内置的认证控制器。如果选择删除这些控制器,可以直接调用 Laravel 的认证类来实现用户认证管理。不用担心,很简单。
我们可以利用 Auth
facade 来访问 Laravel 的认证服务,因此需要确认在类的顶部导入 Auth
facade。接下来让我们看一下 Auth
的 attempt
方法:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
/**
* Handle an authentication attempt.
*
* @return Response
*/
public function authenticate()
{
if (Auth::attempt(['email' => $email, 'password' => $password])) {
// Authentication passed...
return redirect()->intended('dashboard');
}
}
}
attempt
方法会接受一个数组来作为第一个参数,这个数组的值可用来寻找数据库里的用户数据,所以在上面的例子中,用户通过 email
字段被取出,如果用户被找到了,数据库里经过哈希的密码将会与数组中哈希的 password
值比对,如果两个值一样的话就会开启一个通过认证的 session 给用户。
如果认证成功,attempt
方法将会返回 true
,反之则为 false
。
重定向器上的 intended
方法将会重定向用户回原本想要进入的页面,也可以传入一个回退 URI 至这个方法,以避免要转回的页面不可使用。