我们知道laravel在数据库存储时默认的加密算法是Bcrypt,可以使用提供的辅助函数bcrypt 或者使用Hash Facade 来完成密码的加密,使用Laravel的Auth Facade来完成认证,实际上,我们在很多项目因为各种原因并不使用Bcrypt加密存储用户密码,而很多项目还在使用md5或者自己造的乱七八糟的加密方式,这里举个例子使用base64(password + salt)的加密方式来尝试无痛的更换laravel的密码加密方式,从而能够使用laravel的Auth,当然,实际的项目中我相信没人用这样的加密方式。这个例子有助于理解laravel的ServiceProvider(提供给容器怎么获取实例的方法),Facade(给类起个别名并通过魔术方法调用该类中的方法), Contracts(一堆interface)和Container(一个数组中放了很多library的名字,不是类名哦,是自己想起什么起什么)直接上我的烂代码:
首先,我们仿照laravel的原来的Bcrypt的加密实现(BcryptHasher)类去实现laravel的Hasher Contract:
在app下新建一个目录 Password
并新建一个文件 PasswordHasher.php
挨个实现Hasher Contract定义的接口方法:
<?php
namespace App\Password;
use RuntimeException;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
class PasswordHasher implements HasherContract
{
/**
* Default crypt salt factor.
*
* @var string
*/
protected $salt = 'example_string';
/**
* Hash the given value.
*
* @param string $value
* @param array $options
* @return string
*
* @throws \RuntimeException
*/
public function make($value, array $options = [])
{
$hash = base64_encode($value.$this->salt($options));
if ($hash === false) {
throw new RuntimeException('base64 hashing not supported.');
}
return $hash;
}
/**
* Check the given plain value against a hash.
*
* @param string $value
* @param string $hashedValue
* @param array $options
* @return bool
*/
public function check($value, $hashedValue, array $options = [])
{
if (strlen($hashedValue) === 0) {
return false;
}
$hash = base64_encode($value.$this->salt($options));
return (bool) ($hash === $hashedValue);
}
/**
* Check if the given hash has been hashed using the given options.
*
* @param string $hashedValue
* @param array $options
* @return bool
*/
public function needsRehash($hashedValue, array $options = [])
{
return false;
}
/**
* Set the default password work factor.
*
* @param string $salt
* @return $this
*/
public function setSalt($salt)
{
$this->salt = (string) $salt;
return $this;
}
/**
* Extract the cost value from the options array.
*
* @param array $options
* @return string
*/
protected function salt(array $options = [])
{
return isset($options['salt']) ? $options['salt'] : $this->salt;
}
}
所以我们到现在已经掌握了laravel里面的一个装逼的概念名词:Contracts ,他就是定义好的一些接口,我们去实现它就行。
接着我们再在该目录下创建一个文件 PasswordServiceProvider.php
:
<?php
namespace App\Password;
use Illuminate\Support\ServiceProvider;
class PasswordServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('password', function () {
return new PasswordHasher;
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return ['password'];
}
}
在PasswordServiceProvider中我们告诉容器($app即$this->app)password
这个东西就是new PasswordHasher
,这样当你从容器中拿password
,容器就知道到哪去拿,该怎么拿,接着我们把这个ServiceProvider加载到框架中去:
在config/app.php中providers数组中加入
`App\Password\PasswordServiceProvider::class,
现在你可以test一下,打印下$app['password']的值了或者$app->make('password')的值,他们是一样的。所以我们就掌握了ServiceProvider这个装逼的概念。
下面我们在Password目录下,新建一个目录叫Facade
并新建一个文件 Password.php
:
<?php
namespace App\Password\Facade;
use Illuminate\Support\Facades\Facade;
/**
* @see \App\Password\PasswordHasher
*/
class Password extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'password';
}
}
然后我们在config/app.php中的aliases
数组中添加
`'Pwd' => App\Password\Facade\Password::class,//Password被框架的auth.password占用了哦
这样我们在项目中就可以直接使用Pwd::make($value)
来调用PasswordHasher的make方法了。
所以我们又掌握了Facade这个装逼的概念的就是个类起个别名,并且告诉框架使用这个别名真正应该调用容器中的哪个类,这个例子我们通过ServiceProvider告诉Container password 是new PasswordHasher ,Facade 给password 起了个别名叫Pwd,在getFacadeAccessor
方法中告诉了他在容器中的名字叫password。
最后,在完善下,我们在Password目录下建立一个文件叫help.php
:
<?php
if(!function_exists('password')){
/**
* generate password
* @param $value
* @param array $options
* @return mixed
*/
function password($value, $options = [])
{
return app('password')->make($value, $options);
}
}
然后在composer.json中require下面将这个files 加入,运行composer dumpautoload 重新生成加载规则。
这样我们就可以随时使用password($value) 替代Pwd::make($vale) with($app->make('password'))->make($value)等七八种看起来稀奇古怪的写法。
嗯,啥都写好了,怎么在Auth Facade中用呢?
找到配置文件:config/auth.php
我们只需要更改Auth的provider即可,laravel自带的database provider 和eloquent provider 这两个类,都是同时接受一个hasher 和一个database/model,所以我们只需要更改自带的provider的传入参数将现在的PasswordHasher实例传入而不是原来的BcryptHasher,我们来扩展下Auth的provider,修改app/Providers/AuthServiceProvider.php
:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Auth\DatabaseUserProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
//自定义eloquent provider
Auth::provider('custom_eloquent', function () {
$config = $this->app['config']['auth.providers.custom_eloquent'];
return new EloquentUserProvider($this->app['password'], $config['model']);
});
//自定义database provider
Auth::provider('custom_database', function () {
$config = $this->app['config']['auth.providers.custom_database'];
$connection = $this->app['db']->connection();
return new DatabaseUserProvider($connection, $this->app['password'], $config['table']);
});
}
}
这样我们就自己创建了自定义的database和eloquent Auth Provider,改一下配置文件的defualt数组,现在就可以直接使用Auth中的所有方法,并且密码的加密方式已经是自己写的了哦,不要被那些概念唬住了.. 代码最起码要写的不能跟框架格格不入吧,大不了硬编码了,太晚了,睡觉了,马虎结尾了哦...