沙滩星空的博客沙滩星空的博客

laravel用户认证登录详解

新建数据表和模型

新建用户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 AuthenticatesUsersusername()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);
}

未经允许不得转载:沙滩星空的博客 » laravel用户认证登录详解

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址