资讯专栏INFORMATION COLUMN

Laravel 5.2 Auth 认证解析以及改用 salt+passwrod 加密验证

binaryTree / 2791人阅读

摘要:本文来源于本人博客认证解析以及改用加密验证的默认登陆传入邮件和用户密码到方法来认证,通过的值获取,如果用户被找到,经哈希运算后存储在数据中的将会和传递过来的经哈希运算处理的值进行比较。

本文来源于本人博客: Laravel 5.2 Auth 认证解析以及改用 salt+passwrod 加密验证

Larval 5.2的默认Auth登陆传入邮件和用户密码到attempt 方法来认证,通过email 的值获取,如果用户被找到,经哈希运算后存储在数据中的password将会和传递过来的经哈希运算处理的passwrod值进行比较。如果两个经哈希运算的密码相匹配那么将会为这个用户开启一个认证Session。

但是往往我们一些系统中的密码是通过salt+password的方式来做密码认证的,或者一些老的系统是通过salt+passwrod来认证的,现在重构迁移到Laravel框架中,那么密码认证如何不用默认的passwrod的方式而用salt+password的方式认证?

要解决问题,我们最好还是先要弄明白根源,顺藤摸瓜

首先看一下Laravel默认如何做密码验证的,看看 Auth::guard($this->getGuard())->attempt($credentials)方法做了什么:

Illuminate/Contracts/Auth/StatefulGuard.php

namespace IlluminateContractsAuth;

interface StatefulGuard extends Guard
{
    /**
     * Attempt to authenticate a user using the given credentials.
     *
     * @param  array  $credentials
     * @param  bool   $remember
     * @param  bool   $login
     * @return bool
     */
    public function attempt(array $credentials = [], $remember = false, $login = true);
  ......

上面代码看到attemptStatefulGuard 接口中的方法,第一个参数为需要认证的字段,第二个参数为是否记住登陆,第三个参数是否登陆,继续往下看attempt 在SessionGuard中是如何实现的

illuminate/auth/SessionGuard.php

class SessionGuard implements StatefulGuard, SupportsBasicAuth
{
    use GuardHelpers;
    ......
    /**
     * Attempt to authenticate a user using the given credentials.
     *
     * @param  array  $credentials
     * @param  bool   $remember
     * @param  bool   $login
     * @return bool
     */
    public function attempt(array $credentials = [], $remember = false, $login = true)
    {
        $this->fireAttemptEvent($credentials, $remember, $login);

        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);

        if ($this->hasValidCredentials($user, $credentials)) {
            if ($login) {
                $this->login($user, $remember);
            }

            return true;
        }

        return false;
    }
  
   /**
     * Determine if the user matches the credentials.
     *
     * @param  mixed  $user
     * @param  array  $credentials
     * @return bool
     */
    protected function hasValidCredentials($user, $credentials)
    {
        return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
    }
.......
}

看到通过$this->provider->retrieveByCredentials($credentials);$this->provider->validateCredentials($user, $credentials);来实现验证,retrieveByCredentials是用来验证传递的字段查找用户记录是否存在,validateCredentials才是通过用户记录中密码和传入的密码做验证的实际过程。

这里需要注意的是$this->provider,这个provider其实是实现了一个IlluminateContractsAuthUserProviderProvider,我们看到Illuminate/Contracts/Auth下面有两个UserProvider的实现,分别为DatabaseUserProvider.phpEloquentUserProvider.php。但是我们验证密码的时候是通过哪个来验证的是在怎么决定的?

config/auth.php

 "providers" => [
        "users" => [
            "driver" => "eloquent",
            "model" => AppModelsUser::class, //这是User Model
        ],
    ],

这里我配置了 "driver" => "eloquent",那么就是通过EloquentUserProvider.php中的retrieveByCredentials来验证的了,我们继续看看它都干了啥

illuminate/auth/EloquentUserProvider.php

class EloquentUserProvider implements UserProvider
{
......
 /**
     * Retrieve a user by the given credentials.
     *
     * @param  array  $credentials
     * @return IlluminateContractsAuthAuthenticatable|null
     */
    public function retrieveByCredentials(array $credentials)
    {
        // First we will add each credential element to the query as a where clause.
        // Then we can execute the query and, if we found a user, return it in a
        // Eloquent User "model" that will be utilized by the Guard instances.
        $query = $this->createModel()->newQuery();

        foreach ($credentials as $key => $value) {
            if (! Str::contains($key, "password")) {
                $query->where($key, $value);
            }
        }

        return $query->first();
    }
  
   /**
     * Validate a user against the given credentials.
     *
     * @param  IlluminateContractsAuthAuthenticatable  $user
     * @param  array  $credentials
     * @return bool
     */
    public function validateCredentials(UserContract $user, array $credentials)
    {
        $plain = $credentials["password"];

        return $this->hasher->check($plain, $user->getAuthPassword());
    }
    ......
}

上面两个方法 retrieveByCredentials用除了密码以外的验证字段查看记录是否存在,比如用email来查找用户记录是否存在, 然后 validateCredentials 方法就是通过 $this->hasher->check来将输入的密码和哈希的密码比较来验证密码是否正确,$plain 是提交过来的为加密密码字符串,$user->getAuthPassword()是数据库记录存放的加密密码字符串。

好了,看到这里就很明显了,我们需要改成我们自己的密码验证不就是自己实现一下validateCredentials方法就可以了吗,改变 $this->hasher->check为我们自己的密码验证就可以了,开始搞吧!

首先我们来实现$user->getAuthPassword();把数据库中用户表的saltpassword传递到validateCredentials中来:

修改 AppModelsUser.php 添加如下代码

  public function getAuthPassword()
    {
        return ["password" => $this->attributes["password"], "salt" => $this->attributes["salt"]];
    }

然后我们建立一个自己的UserProvider.php 的实现,你可以放到任何地方,我放到自定义目录中:

新建 app/Foundation/Auth/RyanEloquentUserProvider.php

getAuthPassword();
        return sha1($authPassword["salt"] . sha1($authPassword["salt"] . sha1($plain))) == $authPassword["password"];
    }

我这里通过$user->getAuthPassword();传递过来了用户记录的saltpassword,然后将认证提交的密码$plainsalt进行加密,如果加密结果和用户数据库中记录的密码字符串匹配那么认证就通过了, 当然加密的算法完全是自定义的。

最后我们将User Providers换成我们自己的RyanEloquentUserProvider

修改 app/Providers/AuthServiceProvider.php

public function boot(GateContract $gate)
    {
        $this->registerPolicies($gate);

        Auth::provider("ryan-eloquent", function ($app, $config) {
            return new RyanEloquentUserProvider($this->app["hash"], $config["model"]);
        });
    }

修改 config/auth.php

 "providers" => [
        "users" => [
            "driver" => "ryan-eloquent",
            "model" => AppModelsUser::class,
        ],
    ],

好了,再试试可以用过salt+passwrod的方式密码认证了!

转载请注明: 转载自Ryan是菜鸟 | LNMP技术栈笔记

如果觉得本篇文章对您十分有益,何不 打赏一下

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21523.html

相关文章

  • Laravel核心解读 -- 扩展用户认证系统

    摘要:扩展用户认证系统上一节我们介绍了系统实现的一些细节知道了是如何应用看守器和用户提供器来进行用户认证的,但是针对我们自己开发的项目或多或少地我们都会需要在自带的看守器和用户提供器基础之上做一些定制化来适应项目,本节我会列举一个在做项目时遇到的 扩展用户认证系统 上一节我们介绍了Laravel Auth系统实现的一些细节知道了Laravel是如何应用看守器和用户提供器来进行用户认证的,但是...

    王伟廷 评论0 收藏0
  • Laravel核心解读--用户认证系统的实现细节

    摘要:通过装载看守器和用户提供器装载看守器和用户提供器用到的方法比较多,用文字描述不太清楚,我们通过注解这个过程中用到的方法来看具体的实现细节。 用户认证系统的实现细节 上一节我们介绍来Laravel Auth系统的基础知识,说了他的核心组件都有哪些构成,这一节我们会专注Laravel Auth系统的实现细节,主要关注Auth也就是AuthManager是如何装载认证用的看守器(Guard)...

    NicolasHe 评论0 收藏0
  • API Token Authentication

    摘要:新增了很多的新特性,包括了内置多用户认证表单数组输入验证隐式路由模型绑定中间件组的定义中间件访问频率限制等主要功能。相对于变化有点大,简化了的目录结构,并将路由分离出来。由于已将的路由单独分离出来,因此只需在中添加路由规则。 Laravel 5.2 新增了很多的新特性,包括了内置多用户认证、表单数组输入验证、隐式路由模型绑定、中间件组的定义、中间件 throttle 访问频率限制等主要...

    KitorinZero 评论0 收藏0
  • Laravel 多用户认证系统改造方案

    摘要:本文基于,主要介绍如何针对多站点分别进行用户认证的改造,用意是最大限度利用自带的认证系统。具体方案为清晰起见,项目按照不同站点组织成不同模块。学院版用户认证文档版用户认证文档更详细学院版验证文档版验证文档更详细翁航版多用户认证方案 原文发表于 http://www.jianshu.com/p/d6c112f27661 showImg(https://segmentfault.com/i...

    paulli3 评论0 收藏0
  • Laravel 5.5 使用 Jwt-Auth 实现 API 用户认证以及无痛刷新访问令牌

    摘要:默认的时间为周。大概意思就是如果用户有一个,那么他可以带着他的过来领取新的,直到周的时间后,他便无法继续刷新了,需要重新登录。指定在刷新令牌时要保留的声明密钥。为了使令牌无效,您必须启用黑名单。指定用于对用户进行身份验证的提供程序。 showImg(https://segmentfault.com/img/remote/1460000012606251?w=1920&h=1280); ...

    xavier 评论0 收藏0

发表评论

0条评论

binaryTree

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<