新建数据表和模型
新建用户admin_users
数据表和AdminUser
用户模型。
模型必须继承 Illuminate\Foundation\Auth\User
基类。
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
class AdminUser extends Authenticatable{}
更改登录认证配置文件
更改文件 config/auth.php
......
'defaults' => [
'guard' => 'web',
'passwords' => 'admin_users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'admin_users',
],
......
],
'providers' => [
......
'admin_users' => [
'driver' => 'eloquent',
'model' => App\Models\AdminUser::class,
],
],
'passwords' => [
......
'admin_users' => [
'provider' => 'admin_users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
更新配置缓存
更改Laravel配置文件后,必须更新配置缓存
,才能生效!切记!
php artisan config:cache
定义登录成功后默认跳转的页面
修改 App\Providers\RouteServiceProvider
类的 HOME
常量
登录控制器
laravel默认自带一个登录控制器:app/Http/Controllers/Auth/LoginController.php
namespace App\Http\Controllers\Auth;
......
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller{
use AuthenticatesUsers;
protected $redirectTo = RouteServiceProvider::HOME;
public function username():string
{
// POST 过来的字段名 必须和数据库的字段名一模一样
return 'name';
}
protected function loggedOut(Request $request)
{
// 退出登录后的处理方法:跳转到登录页
return redirect('/admin/login');
}
}
如上所示。复写 trait AuthenticatesUsers
的 username()
和 loggedOut()
方法。
登录路由
routes/web.php
Route::post("/admin/login","Auth\LoginController@login");
Route::get("/logout","Auth\LoginController@logout")->name('logout');
浏览器POST提交用户名和密码
请求头示例:Content-Type: application/x-www-form-urlencoded
POST表单数据: _token=NiZMHP4Om4OV92tUb5m384a4bSNud0scCJTgHReg&name=admin&password=123456
用户认证流程解析
登录控制器使用 trait
: use Illuminate\Foundation\Auth\AuthenticatesUsers;
用户认证方法
AuthenticatesUsers.php
登录验证:
namespace Illuminate\Foundation\Auth;
......
use Illuminate\Support\Facades\Auth;
trait AuthenticatesUsers{
use RedirectsUsers, ThrottlesLogins;
public function login(Request $request)
{
......
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
......
return $this->sendFailedLoginResponse($request);
}
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
);
}
......
protected function guard()
{
return Auth::guard();
}
}
$this->guard()
返回一个 \Illuminate\Contracts\Auth\StatefulGuard
实例。
执行该 StatefulGuard
实例的 attempt()
方法,完成登录用户身份认证。
查找 StatefulGuard 类
全局搜索 implements StatefulGuard
,找到类 Illuminate\Auth\SessionGuard
namespace Illuminate\Auth;
......
class SessionGuard implements StatefulGuard, SupportsBasicAuth{
......
public function attempt(array $credentials = [], $remember = false)
{
$this->fireAttemptEvent($credentials, $remember);
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
if ($this->hasValidCredentials($user, $credentials)) {
$this->login($user, $remember);
return true;
}
$this->fireFailedEvent($user, $credentials);
return false;
}
....
/**
* Get the user provider used by the guard.
*
* @return \Illuminate\Contracts\Auth\UserProvider
*/
public function getProvider()
{
return $this->provider;
}
}
关键代码: $this->provider->retrieveByCredentials($credentials);
UserProvider
实例的 retrieveByCredentials
方法,使用POST过来的数组参数,验证用户身份。
UserProvider 类
Illuminate\Auth\EloquentUserProvider
namespace Illuminate\Auth;
......
use Illuminate\Contracts\Auth\UserProvider;
class EloquentUserProvider implements UserProvider{
public function __construct(HasherContract $hasher, $model)
{
$this->model = $model;
$this->hasher = $hasher;
}
}
CreatesUserProviders
namespace Illuminate\Auth;
......
trait CreatesUserProviders
{
public function createUserProvider($provider = null)
{
......
switch ($driver) {
case 'database':
return $this->createDatabaseProvider($config);
case 'eloquent':
return $this->createEloquentProvider($config);
......
}
}
protected function createEloquentProvider($config)
{
return new EloquentUserProvider($this->app['hash'], $config['model']);
}
}
AuthManager
用户身份认证管理中心: Illuminate\Auth\AuthManager
namespace Illuminate\Auth;
......
class AuthManager implements FactoryContract
{
use CreatesUserProviders;
public function createSessionDriver($name, $config)
{
$provider = $this->createUserProvider($config['provider'] ?? null);
$guard = new SessionGuard($name, $provider, $this->app['session.store']);
......
return $guard;
}
public function getDefaultDriver()
{
return $this->app['config']['auth.defaults.guard'];
}
public function guard($name = null)
{
$name = $name ?: $this->getDefaultDriver();
return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
}
protected function getConfig($name)
{
return $this->app['config']["auth.guards.{$name}"];
}
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new InvalidArgumentException("Auth guard [{$name}] is not defined.");
}
// 这个是自定义看守器
if (isset($this->customCreators[$config['driver']])) {
return $this->callCustomCreator($name, $config);
}
// 系统自带的guard看守器: createSessionDriver or createTokenDriver
$driverMethod = 'create'.ucfirst($config['driver']).'Driver';
if (method_exists($this, $driverMethod)) {
return $this->{$driverMethod}($name, $config);
}
......
}
}
AuthManager类关键代码为 public function guard($name = null)
方法。guard()方法
,可根据config/auth.php
文件配置,获取对应的身份验证看守器
。
魔术方法 __call()
,使得AuthManager类实例,若调用到不存在的方法,都会定位到默认的身份验证看守器(guard)
的方法。
public function __call($method, $parameters)
{
return $this->guard()->{$method}(...$parameters);
}