修改laravel5.3的密码验证
来源:互联网 发布:闲鱼淘宝二手手机 编辑:程序博客网 时间:2024/05/16 08:59
如何使用自定义的密码加密和验证方法?从网上找到了解决办法,现记录下来,一方面加深印象,另一方面写成blog备查。
从这篇文章可以了解laravel的认证流程:http://www.tuicool.com/articles/Av2aMb2。
按照文章中的办法,在app下新建文件夹hash,然后新建两个类文件:EloquentUserProvider.php和Security.php
Security.php内容:
namespace App\hash;use Illuminate\Contracts\Hashing\Hasher;/** * 加密类库,移植自Yii2.0的Security类 */class Security implements Hasher{ public $passwordHashCost = 13; private $_useLibreSSL; private $_randomFile; /** * Generates specified number of random bytes. * Note that output may not be ASCII. * @see generateRandomString() if you need a string. * * @param integer $length the number of bytes to generate * @return string the generated random bytes * @throws InvalidParamException if wrong length is specified * @throws Exception on failure. */ public function generateRandomKey($length = 32) { if (!is_int($length)) { throw new Exception('First parameter ($length) must be an integer'); } if ($length < 1) { throw new Exception('First parameter ($length) must be greater than 0'); } // always use random_bytes() if it is available if (function_exists('random_bytes')) { return random_bytes($length); } // The recent LibreSSL RNGs are faster and likely better than /dev/urandom. // Parse OPENSSL_VERSION_TEXT because OPENSSL_VERSION_NUMBER is no use for LibreSSL. // https://bugs.php.net/bug.php?id=71143 if ($this->_useLibreSSL === null) { $this->_useLibreSSL = defined('OPENSSL_VERSION_TEXT') && preg_match('{^LibreSSL (\d\d?)\.(\d\d?)\.(\d\d?)$}', OPENSSL_VERSION_TEXT, $matches) && (10000 * $matches[1]) + (100 * $matches[2]) + $matches[3] >= 20105; } // Since 5.4.0, openssl_random_pseudo_bytes() reads from CryptGenRandom on Windows instead // of using OpenSSL library. LibreSSL is OK everywhere but don't use OpenSSL on non-Windows. if ($this->_useLibreSSL || ( DIRECTORY_SEPARATOR !== '/' && substr_compare(PHP_OS, 'win', 0, 3, true) === 0 && function_exists('openssl_random_pseudo_bytes') ) ) { $key = openssl_random_pseudo_bytes($length, $cryptoStrong); if ($cryptoStrong === false) { throw new Exception( 'openssl_random_pseudo_bytes() set $crypto_strong false. Your PHP setup is insecure.' ); } if ($key !== false && StringHelper::byteLength($key) === $length) { return $key; } } // mcrypt_create_iv() does not use libmcrypt. Since PHP 5.3.7 it directly reads // CryptGenRandom on Windows. Elsewhere it directly reads /dev/urandom. if (function_exists('mcrypt_create_iv')) { $key = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); if (StringHelper::byteLength($key) === $length) { return $key; } } // If not on Windows, try to open a random device. if ($this->_randomFile === null && DIRECTORY_SEPARATOR === '/') { // urandom is a symlink to random on FreeBSD. $device = PHP_OS === 'FreeBSD' ? '/dev/random' : '/dev/urandom'; // Check random device for special character device protection mode. Use lstat() // instead of stat() in case an attacker arranges a symlink to a fake device. $lstat = @lstat($device); if ($lstat !== false && ($lstat['mode'] & 0170000) === 020000) { $this->_randomFile = fopen($device, 'rb') ?: null; if (is_resource($this->_randomFile)) { // Reduce PHP stream buffer from default 8192 bytes to optimize data // transfer from the random device for smaller values of $length. // This also helps to keep future randoms out of user memory space. $bufferSize = 8; if (function_exists('stream_set_read_buffer')) { stream_set_read_buffer($this->_randomFile, $bufferSize); } // stream_set_read_buffer() isn't implemented on HHVM if (function_exists('stream_set_chunk_size')) { stream_set_chunk_size($this->_randomFile, $bufferSize); } } } } if (is_resource($this->_randomFile)) { $buffer = ''; $stillNeed = $length; while ($stillNeed > 0) { $someBytes = fread($this->_randomFile, $stillNeed); if ($someBytes === false) { break; } $buffer .= $someBytes; $stillNeed -= StringHelper::byteLength($someBytes); if ($stillNeed === 0) { // Leaving file pointer open in order to make next generation faster by reusing it. return $buffer; } } fclose($this->_randomFile); $this->_randomFile = null; } throw new Exception('Unable to generate a random key'); } /** * Generates a random string of specified length. * The string generated matches [A-Za-z0-9_-]+ and is transparent to URL-encoding. * * @param integer $length the length of the key in characters * @return string the generated random key * @throws Exception on failure. */ public function generateRandomString($length = 32) { if (!is_int($length)) { throw new Exception('First parameter ($length) must be an integer'); } if ($length < 1) { throw new Exception('First parameter ($length) must be greater than 0'); } $bytes = $this->generateRandomKey($length); // '=' character(s) returned by base64_encode() are always discarded because // they are guaranteed to be after position $length in the base64_encode() output. return strtr(substr(base64_encode($bytes), 0, $length), '+/', '_-'); } /** * Generates a secure hash from a password and a random salt. * * The generated hash can be stored in database. * Later when a password needs to be validated, the hash can be fetched and passed * to [[validatePassword()]]. For example, * * ```php * // generates the hash (usually done during user registration or when the password is changed) * $hash = Yii::$app->getSecurity()->generatePasswordHash($password); * // ...save $hash in database... * * // during login, validate if the password entered is correct using $hash fetched from database * if (Yii::$app->getSecurity()->validatePassword($password, $hash) { * // password is good * } else { * // password is bad * } * ``` * * @param string $password The password to be hashed. * @param integer $cost Cost parameter used by the Blowfish hash algorithm. * The higher the value of cost, * the longer it takes to generate the hash and to verify a password against it. Higher cost * therefore slows down a brute-force attack. For best protection against brute-force attacks, * set it to the highest value that is tolerable on production servers. The time taken to * compute the hash doubles for every increment by one of $cost. * @return string The password hash string. When [[passwordHashStrategy]] is set to 'crypt', * the output is always 60 ASCII characters, when set to 'password_hash' the output length * might increase in future versions of PHP (http://php.net/manual/en/function.password-hash.php) * @throws Exception on bad password parameter or cost parameter. * @see validatePassword() */ public function generatePasswordHash($password, $cost = null) { if ($cost === null) { $cost = $this->passwordHashCost; } if (function_exists('password_hash')) { /** @noinspection PhpUndefinedConstantInspection */ return password_hash($password, PASSWORD_DEFAULT, ['cost' => $cost]); } $salt = $this->generateSalt($cost); $hash = crypt($password, $salt); // strlen() is safe since crypt() returns only ascii if (!is_string($hash) || strlen($hash) !== 60) { throw new Exception('Unknown error occurred while generating hash.'); } return $hash; } /** * Verifies a password against a hash. * @param string $password The password to verify. * @param string $hash The hash to verify the password against. * @return boolean whether the password is correct. * @throws InvalidParamException on bad password/hash parameters or if crypt() with Blowfish hash is not available. * @see generatePasswordHash() */ public function validatePassword($password, $hash) { if (!is_string($password) || $password === '') { throw new Exception('Password must be a string and cannot be empty.'); } if (!preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hash, $matches) || $matches[1] < 4 || $matches[1] > 30 ) { throw new Exception('Hash is invalid.'); } if (function_exists('password_verify')) { return password_verify($password, $hash); } $test = crypt($password, $hash); $n = strlen($test); if ($n !== 60) { return false; } return $this->compareString($test, $hash); } /** * Generates a salt that can be used to generate a password hash. * * The PHP [crypt()](http://php.net/manual/en/function.crypt.php) built-in function * requires, for the Blowfish hash algorithm, a salt string in a specific format: * "$2a$", "$2x$" or "$2y$", a two digit cost parameter, "$", and 22 characters * from the alphabet "./0-9A-Za-z". * * @param integer $cost the cost parameter * @return string the random salt value. * @throws InvalidParamException if the cost parameter is out of the range of 4 to 31. */ protected function generateSalt($cost = 13) { $cost = (int) $cost; if ($cost < 4 || $cost > 31) { throw new Exception('Cost must be between 4 and 31.'); } // Get a 20-byte random string $rand = $this->generateRandomKey(20); // Form the prefix that specifies Blowfish (bcrypt) algorithm and cost parameter. $salt = sprintf("$2y$%02d$", $cost); // Append the random salt data in the required base64 format. $salt .= str_replace('+', '.', substr(base64_encode($rand), 0, 22)); return $salt; } /** * Performs string comparison using timing attack resistant approach. * @see http://codereview.stackexchange.com/questions/13512 * @param string $expected string to compare. * @param string $actual user-supplied string. * @return boolean whether strings are equal. */ public function compareString($expected, $actual) { $expected .= "\0"; $actual .= "\0"; $expectedLength = StringHelper::byteLength($expected); $actualLength = StringHelper::byteLength($actual); $diff = $expectedLength - $actualLength; for ($i = 0; $i < $actualLength; $i++) { $diff |= (ord($actual[$i]) ^ ord($expected[$i % $expectedLength])); } return $diff === 0; } public function make($value, array $options = []) { return $this->generatePasswordHash($value); } public function check($password, $hashedValue, array $options = []) { if (!is_string($password) || $password === '') { throw new Exception('Password must be a string and cannot be empty.'); } if (!preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hashedValue['password'], $matches) || $matches[1] < 4 || $matches[1] > 30 ) { throw new Exception('Hash is invalid.'); } if (function_exists('password_verify')) { return password_verify($password, $hashedValue['password']); } $test = crypt($password, $hashedValue['password']); $n = strlen($test); if ($n !== 60) { return false; } return $this->compareString($test, $hashedValue['password']); } public function needsRehash($hashedValue, array $options = []) { return false; }}
类中实现了3个方法:make -- 加密密码,check -- 校验密码,needsRehash -- 暂不支持。
新注册用户时,将会调用make方法生成加密的密码;用户登录时,调用check校验密码。
EloquentUserProvider.php内容:
<?phpnamespace App\hash;use Illuminate\Auth\EloquentUserProvider;use Illuminate\Contracts\Auth\Authenticatable;use Illuminate\Support\Str;class EloquentUserProvider extends EloquentUserProvider{/** * Validate a user against the given credentials. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param array $credentials * @return bool */public function validateCredentials(Authenticatable $user, array $credentials){$plain = $credentials['password'];$authPassword = $user->getAuthPassword();//return bcrypt($plain) === $authPassword['password'];return $this->hasher->check($plain, $authPassword);}}
类中实现了一个方法:validateCredentials -- 校验用户密码
然后需要修改User类,添加getAuthPassword方法:
public function getAuthPassword() { return ['password' => $this->attributes['password_hash']]; }
使用命令行:
php artisan make:provider HashServiceProvider
此命令会在app/Providers下创建文件:HashServiceProvider.php,打开这个文件,在register方法中添加下面代码:
$this->app['hash'] = $this->app->share(function() { return new \App\hash\Security();});上面的代码注册新的hash类为刚才的Security类。
修改config/app.php文件引用适配器:
//注释掉这一行//Illuminate\Hashing\HashServiceProvider::class,//添加下面这一行App\Providers\HashServiceProvider::class,
做完上述工作后,需要修改laravel的Auth适配器为我们自己的适配器:
打开app/Providers/AuthServiceProvider.php,修改boot方法:
public function boot() { $this->registerPolicies(); \Auth::provider('my-eloquent', function($app, $config) { return new \App\hash\EloquentUserProvider($this->app['hash'], $config['model']); }); }打开config/auth.php,修改providers数组内容:
'users' => [ 'driver' => 'my-eloquent', 'model' => App\User::class, ],
0 0
- 修改laravel5.3的密码验证
- javascript 密码修改验证
- ajax验证修改密码
- 一份修改layui自定义验证信息的修改密码功能
- Laravel5.3 使用默认api验证登陆
- Laravel5.3使用auth登录验证
- C#密码修改及验证
- bootstrapvalidator 插件密码修改验证
- C#中常用到的密码修改及正则验证代码
- mysql跳过密码验证修改密码
- laravel5验证码
- laravel5验证码
- laravel5验证码
- laravel5 验证码
- laravel5表单唯一验证
- laravel5.2 验证码
- laravel5验证码
- Laravel5.2 关于$errors变量的问题 form 表单验证
- poj_2442_Sequence_堆
- gulp入坑系列(1)——安装gulp
- hadoop学习第四节:HDFS
- tomcat中设置默认项目
- [BZOJ2959]长跑(lct+并查集)
- 修改laravel5.3的密码验证
- Linux(Ubuntu)下PostGIS+Postgresql的安装与配置(下)
- POJ 2236 Wireless Network 笔记
- 对DataTable进行过滤筛选的一些方法Select,dataview
- Material Design动画(三)
- 固定子元素相对于父元素的位置
- Scalable Architecture DR CoN: Docker, Registrator, Consul, Consul Template and Nginx
- 修改informatica数据库的连接信息
- Win7 已经是管理员身份,操作时还提示权限不够?