因为之前的项目是基于yaf的,个人觉得开发相率上laravel 更好,所以迁移到laravel上使用。这就会遇到一个兼容性的问题,比如用户登录就不行,以前加密方式也是自己写的,所以迁移起来,首先就要解决用户登录问题了
laravel 自带的登录
App\Http\Controllers\Auth\LoginController
里面用了一个trait AuthenticatesUsers
,主要的登录逻辑在这里:
-
showLoginForm
显示登录界面 -
login
处理登录请求 -
validateLogin
验证登录请求信息 -
attemptLogin
登录(重要) -
credentials
过滤不需要的请求信息 -
sendLoginResponse
返回成功登录信息 -
authenticated
认证 -
sendFailedLoginResponse
返回登录失败信息 -
username
默认使用登录的字段,(如果你使用的是phone,那么重写这个方法就可以了) -
logout
退出登录 -
guard
获取守卫者
具体的细节就不说了,主要就看attemptLogin
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->has('remember')
);
}
protected function guard()
{
return Auth::guard();
}
$this->guard()
就是获取到Auth:guard()
,那么这个facade
又是什么呢,看一下这个facade
:
protected static function getFacadeAccessor()
{
return 'auth';
}
那么看一下Illuminate\Foundation\Application
的registerCoreContainerAliases
(别问我怎么一下找到Application来的,以后有机会说一下facade):
public function registerCoreContainerAliases()
{
foreach ([
'app' => [\Illuminate\Foundation\Application::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
'auth' => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
'auth.driver' => [\Illuminate\Contracts\Auth\Guard::class],
'blade.compiler' => [\Illuminate\View\Compilers\BladeCompiler::class],
'cache' => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
....
//省略
可以看到auth
就是\Illuminate\Contracts\Auth\Factory::class
的具体实现类\Illuminate\Auth\AuthManager::class
,那么我们就可以找到上文说的guard
:
public function guard($name = null)
{
$name = $name ?: $this->getDefaultDriver();
return isset($this->guards[$name])
? $this->guards[$name]
: $this->guards[$name] = $this->resolve($name);
}
public function getDefaultDriver()
{
return $this->app['config']['auth.defaults.guard'];
}
这里就看到了,默认是config
中auth.php
的配置项web
:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
接着看$this->resolve('web')
是返回了什么鬼:
protected function resolve($name)
{
$config = $this->getConfig($name);
//$config=[ 'driver' => 'session', 'provider' => 'users']
if (is_null($config)) {
throw new InvalidArgumentException("Auth guard [{$name}] is not defined.");
}
if (isset($this->customCreators[$config['driver']])) {
return $this->callCustomCreator($name, $config);
}
//$driverMethod=createSessionDriver
$driverMethod = 'create'.ucfirst($config['driver']).'Driver';
if (method_exists($this, $driverMethod)) {
return $this->{$driverMethod}($name, $config);
}
throw new InvalidArgumentException("Auth guard driver [{$name}] is not defined.");
}
由上面可以知道,最后跑到了createSessionDriver
这个方法了:
//$config=[ 'driver' => 'session', 'provider' => 'users']
public function createSessionDriver($name, $config)
{
//$provider=EloquentUserProvider($this->app['hash'], $config['model']);
$provider = $this->createUserProvider($config['provider'] ?? null);
$guard = new SessionGuard($name, $provider, $this->app['session.store']);
if (method_exists($guard, 'setCookieJar')) {
$guard->setCookieJar($this->app['cookie']);
}
if (method_exists($guard, 'setDispatcher')) {
$guard->setDispatcher($this->app['events']);
}
if (method_exists($guard, 'setRequest')) {
$guard->setRequest($this->app->refresh('request', $guard, 'setRequest'));
}
return $guard;
}
public function createUserProvider($provider = null)
{
//$provider=user
if (is_null($config = $this->getProviderConfiguration($provider))) {
return;
}
//$config= ['driver' => 'eloquent','model' => App\User::class,]
//我们没有自定义自己的提供器,所以这一坨跳过,那么怎么自定义自己的呢,使用Auth::provider
//
//public function provider($name, Closure $callback)
//{
// $this->customProviderCreators[$name] = $callback;
//
// return $this;
// }
// 具体可以看文档https://d.laravel-china.org/docs/5.5/authentication
if (isset($this->customProviderCreators[$driver = ($config['driver'] ?? null)])) {
return call_user_func(
$this->customProviderCreators[$driver], $this->app, $config
);
}
//$driver=eloquent
switch ($driver) {
case 'database':
return $this->createDatabaseProvider($config);
case 'eloquent':
//return new EloquentUserProvider($this->app['hash'], $config['model']);
return $this->createEloquentProvider($config);
default:
throw new InvalidArgumentException(
"Authentication user provider [{$driver}] is not defined."
);
}
}
所以Auth::guard()
最后返回一个SessionGuard
实例,接着看一下sessionGuard
里面找一下attempt
方法:
// $this->guard()->attempt($this->credentials($request), $request->has('remember'));
public function attempt(array $credentials = [], $remember = false)
{
//很任性的不管
$this->fireAttemptEvent($credentials, $remember);
//$this->provider 就是上面的 EloquentUserProvider($this->app['hash'], $config['model']);
//具体就是查找用户,太简单了,不说了
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
//这里就是验证用户密码是不是相同的地方
if ($this->hasValidCredentials($user, $credentials)) {
$this->login($user, $remember);
return true;
}
$this->fireFailedEvent($user, $credentials);
return false;
}
protected function hasValidCredentials($user, $credentials)
{
return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
}
可以看最后是在EloquentUserProvider
里面验证了用户的密码是不是相同:
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
return $this->hasher->check($plain, $user->getAuthPassword());
}
所有到这里我们就找到问题的根源了(你说是不是很蛋疼,找一个问题费老大劲),那么我们要解决旧系统的密码加密问题,有两个办法:
-
自定义用户提供器
(目前不就是使用的EloquentUserProvider
,’我们自定义一个,再重写一下validateCredentials
就可以了) - 重写
$this->hasher
感觉一次写的有点多了,下次在写具体方法吧