Laravel太不灵活了,换个加密方式麻烦的要死

想把默认的bcrypt密码加密方式换成md5+salt,在不改vendor的情况下很麻烦,不知道为什么laravel非要把bcrypt作为默认加密方式写到vendor里面?就算自己写service也是有很多相关的东西是写死在vendor里面的,这点觉得很不爽啊

JellyBool

虽然说我不提倡这种做法,但可以尝试下面的步骤:

  1. app/下创建一个MD5/文件夹。里面创建一个MD5Hasher类

(MD5Hasher.php)

class MD5Hasher implements Illuminate/Contracts/Hashing/Hasher {

    /**
     * Hash the given value.
     *
     * @param  string  $value
     * @return array   $options
     * @return string
     */
    public function make($value, array $options = []) {
        return md5($value);//你可以在这里实现你想要的加密方式
    }

    /**
     * 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 = []) {
        return $this->make($value) === $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;
    }

}

make your provider

命令行:

php artisan make:provider MD5HashServiceProvider

在这个文件的register()方法写上:

public function register()
    {
        $this->app['hash'] = $this->app->share(function () {
            return new MD5Hasher();
        });
    }

修改配置

config/app.php,注释下面这一行:

 Illuminate\Hashing\HashServiceProvider::class,

加上你的:

MD5HashServiceProvider::class

Happy Hacking

peinhu

@JellyBool 感谢回复,我自己搞搞已经做到你这一步了,但困扰的地方就是我这边是md5+salt,现在的问题就是不知道如何把已经存在数据库中的salt带进去?你这边好像也没有给出,我采用的是md5(password.password.salt)

JellyBool

你说说你的具体方案?就是你想怎样实现这个过程?我看看有没有解决方法…因为就目前的信息,我貌似还不清楚你要什么样的过程?比如我不知道你存数据库的盐值到底是怎么存的,它是怎么来的等等,整个你想实现的流程说一下?

peinhu

@JellyBool 其实就是把密码加密的方式从bcrypt(password)改成md5(password+salt),数据库中就是增加了一个salt字段,用户注册的时候会自动随机生成一个N位salt字符串,现在注册和密码重设的那部分都已经解决了,就是在验证部分遇到了问题,因为laravel把验证部分写死在vendor里,具体见Illuminate\Auth\EloquentUserProvider中的validateCredentials()方法,$this->hasher可以用自己的service替换,但是check()方法它写死了,它只check你hash(password)后的值是否等于数据库字段中的值,可是我这边还有salt,是不是要把EloquentUserProvider也重写或者覆盖?

JellyBool

首先说明两个想法:
第一,上面的check方法不起作用?

 public function check($value, $hashedValue, array $options = []) {
        return $this->make($value) === $hashedValue;
    }

我看了validateCredentials(),貌似并没有什么影响?你是在哪出的问题?我实际来一把试试

peinhu

@JellyBool 其实就是要带入salt的问题,你的例子中没有获取salt的部分,验证必需是md5(提交的password+数据库中读取的用户salt)

JellyBool

我试了一下,上面的方法完全没有问题。比如在用户注册的时候,可以使用

$input['salt'] = str_random(32);

然后密码就直接使用:

$input['password'] = Hash::make($input['password'].$input['salt']);

之后保存,最后在验证的时候使用check()就可以了;

peinhu

@JellyBool 注册是没问题,但登录认证的时候就有问题了,登录时你是通过什么把salt值带到自己写的hash方法中的?你之前的MD5Hasher服务的make方法中并没有带入任何salt值呀
public function make($value, array options = []) { return md5(value);//你可以在这里实现你想要的加密方式
}

JellyBool

登录的时候你不是可以拿到用户的email么,有了email必然可以拿到salt和加密密码字符串啊,有了这两个,怎么都解决了啊

peinhu

@JellyBool 那样需要改vendor中的文件了,登录过程是在Illuminate\Auth\Guard的attempt方法中实现的,也是写死的。

JellyBool

你不用attempt方法判断就可以了啊,举个例子说,你就判断从邮箱拿到的的用户,他的密码是否等于用户输入的密码和盐值的md5值就可以了啊,如果相等,就直接

if($user->password === md5($input['password'].$user->salt)){

Auth::login($user);

}
zghack

单独的

zghack

make

tbuijibing

我的更变态 md5(md5(pwd).salt);

sodasix

double MD5

justtest

我是 v2ex 上回复你帖子的人,当时扫读比较快,没看到你是有 salt 的,和二楼给你的方法差不多,都不能直接解决问题,但也都算把核心部分告诉你了。

其实你要是换个谦逊友好点的语气,我或许会帮你多看几眼代码,但是看到你在两个地方都用负面、消极的激将语气,多少还是有点抵触。 要知道, 对于普通开发者来说,绝大多数的所谓“坑”,都是自己能力不足造成的。 Laravel 作者写程序十几年,能写到让你改 vendor 才解决需求的地步?

上次回你的时候记得扫了一遍登录部分的文件,我当时还下了几个断点,记得没错的话,基本增加一两个方法就解决这点事,再瞅瞅你那一脸埋怨的表情,唉,算了。在 v2ex 回你都后老悔了。

peinhu

@justtest 得,需要这么较真吗?Laravel作为一个吹牛吹那么厉害人气那么高的框架,我用下来也觉得不错,但是在使用过程中却被这个问题困扰了好几天,心里是比较急躁的,因为这个登陆验证从整个项目来说只是第一步,然而第一步就卡壳了,下面的怎么办。这很打击人的积极性,我有将近好几天的时间都在看登陆、验证、找回那部分的框架源码,一个框架,在你必须看源码的基础上才能用?这个在之前我是从来没遇到过的,我之前用thinkphp做项目,从来没看过它的源码,手册写得很详尽,再不行搜索一下也解决问题了。然而Laravel的这个问题搜索谷歌也没有好的答案,所以只能自己去提问了,想有个高手能给出合适的解决方法,可是问遍了各大论坛社区甚至国外的laravel.io,都没有人能给出满意的答案。
你们说的那些方法其实我在提问之前都已经用过了,这个问题难点是Laravel控制了整个验证登陆的流程,我所做的只是改了hash方法,但是流程还是原来的,里面并没有获取salt的代码,然而只有在这个流程里才能获得salt。。。所以结论就是必须把控制验证流程的相关方法给覆写了,那样相当于要覆写Eloquent,所以具体要怎么做我还不清楚。
现在我已经放弃改成md5+salt了,确实麻烦的要死,就算像你说的只要增加一两个方法就能解决,但是不知道你试过没有,注册、验证、找回这几个环节并不是共用一个东西的,你还是要改好几个地方。本来我想的是都说Laravel低耦合很灵活,我只要把某个service替换成自己的就万事大吉了,谁知道并不是这么简单的一件事,是我太理想化了。
虽然我最后放弃了这个修改,但是还是给后来人一些参考吧。其实有一个取巧的办法,就是用md5(password)来代替salt,这样就不用去数据库取salt值了,即加密方式为md5(password+md5(password))。这只需要改写替换一下默认的HashService就行了,不用改流程。但是这样做有个弊端,就是相同密码的用户hash出来的值是一样的,一定程度上降低了安全性。
最后,我想说明一下你认为我用那样的语气态度不好,其实是因为我心里已经比较急躁了,想快点吸引更多的人来关注,从而解决这个卡住我好几天的问题,并不是我故意以这样的态度来提问。其实这个问题也不是我一个人碰到的,v2的那个楼主就也碰到了,同样也找不到方法,说不定还有更多的人在这个问题上卡住。如果我不那么说,不用那样的语气,也许没人会来关注也没人回复,这个问题也就无解了。

peinhu

@tbuijibing 请问下,你是如何在验证时获取到salt的?

null
salt mark 
必趣网朱其鹏

@JellyBool 谢谢,您的解决了我的疑惑

QQ634381967

http://www.bcty365.com/content-153-5886-1.html laravel5.4 登录注册MD5加密方式教程