为了兼容minecraft的authme密码hash方式,我们不能使用laravel自带的BcryptHash。所以我们需要对登录流程进行一些修改。
首先我们来看原来的BcryptHash是在哪里使用的
#vendor\laravel\framework\src\Illuminate\Auth\CreatesUserProviders.php /** * Create an instance of the Eloquent user provider. * * @param array $config * @return \Illuminate\Auth\EloquentUserProvider */ protected function createEloquentProvider($config) { return new EloquentUserProvider($this->app['hash'], $config['model']); }
这里我们发现当创建默认的EloquentUserProvider时,laravel自带hash,也就是Bcrypt被作为参数传递了,所以我们就要想办法让这里不使用自带hash,而在这里直接更改是不行的,因为这是laravel的源码,我们是不能修改的。
我们转而把注意力放在自定义UserProvider上,自定义之后我们当然就能使用自己的hash方式了。下面是一个例子(http://laravelacademy.org/post/5974.html)
#app\Providers\AuthServiceProvider.php <?php namespace App\Providers; use Illuminate\Support\Facades\Auth; use App\Extensions\RiakUserProvider; use Illuminate\Support\ServiceProvider; class AuthServiceProvider extends ServiceProvider { /** * Register any application authentication / authorization services. * * @return void */ public function boot() { $this->registerPolicies(); Auth::provider('riak', function($app, array $config) { // Return an instance of Illuminate\Contracts\Auth\UserProvider... return new RiakUserProvider($app->make('riak.connection')); }); } }
但是这时候我们发现,其实我们完全还可以在这里继续使用EloquentUserProvider,因为我们的目的只是更改hash方式,只需要在上面实例化EloquentUserProvider的地方,将我们自己的Hash类作为第一个参数传递进去就好了。
首先,我们先写好我们自己的Hash类,根据EloquentUserProvider的源码,我们发现我们的Hash类必须是Illuminate\Contracts\Hashing\Hasher契约的实现,契约的源码如下
interface Hasher { /** * Hash the given value. * * @param string $value * @param array $options * @return string */ public function make($value, array $options = []); /** * 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 = []); /** * 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 = []); }
我们只需要补全上面的方法,实现这个接口即可,下面是我们自定义的AuthmeHasher
namespace App\Libraries\Hashing; use Illuminate\Contracts\Hashing\Hasher as HasherContract; class AuthmeHasher implements HasherContract{ /** * Hash the given value. * * @param string $value * @param array $options * @return string */ public function make($value, array $options = []){ $p1 = '$SHA'; $p2 = str_random(16); $p3 = hash('sha256', hash('sha256', $value) . $p2); $hash = join('$',[$p1,$p2,$p3]); 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; } $parts = explode('$', $hashedValue); return count($parts) === 4 && $parts[3] === hash('sha256', hash('sha256', $value) . $parts[2]); } /** * 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 = []){ if (strlen($hashedValue) === 0) { return false; } return $hashedValue; } }
这里由于不知道needsRehash方法该如何写,所以我直接返回了原先的hashedValue。具体这个文件的写法,我们也可以参考laravel默认的vendor\laravel\framework\src\Illuminate\Hashing\BcryptHasher.php
接下来就是最关键的部分了,我们将自己的AuthmeHash注入到EloquentUserProvider
#app\Providers\AuthServiceProvider.php namespace App\Providers; use Auth; use Illuminate\Auth\EloquentUserProvider; use App\Libraries\Hashing\AuthmeHasher; use Illuminate\Support\Facades\Gate; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; 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(); //使用authme的Hash来处理密码 Auth::provider('authme', function($app, array $config) { return new EloquentUserProvider(new AuthmeHasher,$config['model']); }); } }
当然,最后别忘了设置config\auth.php下面的providers中driver为你上面在Auth::provider中声明的名字
/* |-------------------------------------------------------------------------- | User Providers |-------------------------------------------------------------------------- | | All authentication drivers have a user provider. This defines how the | users are actually retrieved out of your database or other storage | mechanisms used by this application to persist your user's data. | | If you have multiple user tables or models you may configure multiple | sources which represent each model / table. These sources may then | be assigned to any extra authentication guards you have defined. | | Supported: "database", "eloquent" | */ 'providers' => [ 'users' => [ 'driver' => 'authme', 'model' => App\User::class, ], // 'users' => [ // 'driver' => 'database', // 'table' => 'users', // ], ],
在最后还是说一句,学习Laravel阅读源码还是关键,文档的作用有的时候比较有局限性。本篇文章参考了http://blueve.me/archives/898的一些信息
Pingback引用通告: Laravel 5.3 让用户使用明文密码并登陆 – Onlyke