【问题标题】:Yii2 ldap identity set up after authenticationYii2 ldap 身份认证后设置
【发布时间】:2015-05-05 08:12:18
【问题描述】:

我是 Yii2 的新手,我需要使用 ldap 创建一个登录系统。关于它的信息不多,所以我希望有人能帮助我。

我安装了 edvlerblog/yii2-adldap-module 并且我已经成功实现了身份验证。

我的问题是,我希望在登录后拥有与使用高级模板相同的用户身份,并能够使用 Yii::$app->user 功能。

官方示例通过 ActiveRecord 创建实现 IdentityInterface 的 User:

http://www.yiiframework.com/doc-2.0/yii-web-identityinterface.html

我还发现了很多关于 Yii 版本 1 的示例。这是一个很好的例子:

https://www.exchangecore.com/blog/yii-active-directory-useridentity-login-authentication/

但仍然无法使其工作...可能是概念问题或语法问题,但无论如何我真的很感谢这里的一些帮助。

models/LoginForm.php 认证方式:

public function validatePasswordLdap($attribute, $params)
{
    if (!$this->hasErrors()) {
        $user = $this->getUserLdap();
        if (!$user || !Yii::$app->ldap->authenticate($this->username,$this->password)) {
            $this->addError($attribute, 'Incorrect username or passwords.');
        }
    }
}

models/LoginForm.php 登录方式:

public function loginLdap()
{
    if ($this->validate()) {
        return Yii::$app->user->login($this->getUserLdap(), $this->rememberMe ? 3600 * 24 * 30 : 0);
    } else {
        return false;
    }
}

最后一个,getUser 方法。 UserLdap 正在实施 IdentityInterface 但我不知道如何正确执行:

public function getUserLdap()
{
    if ($this->_user === false) {           
        $this->_user = UserLdap::findIdentity($this->username);
    }

    return $this->_user;
}

【问题讨论】:

    标签: authentication ldap yii2 yii2-advanced-app yii2-user


    【解决方案1】:

    我终于明白了其中的逻辑:

    • 当您登录到 LoginForm.php 视图时,获取用户名和密码并使用 validatePasswordLdap 进行验证。您必须在规则中指定验证密码的函数。

    • 然后如果 validate() 是 OK 的,它会使用登录中引入的用户名调用 FindIdentity。此函数必须返回一个 IdentityInterface 对象,因此首先您需要创建 User 对象,设置参数(电子邮件、电话、姓名等)并返回它。

    • 要在整个站点中使用登录/注销功能和 isGuest,您只需执行下面的 loginLdap 函数并将此用户对象传递给 Yii::$app->user->login 方法。

    代码如下所示:

    LoginForm.php

    public function rules()
    {
        return [
            // username and password are both required
            [['username', 'password'], 'required'],
            // rememberMe must be a boolean value
            ['rememberMe', 'boolean'],
           // password is validated by validatePassword()
            ['password', 'validatePasswordLdap'],
        ];
    }
    
    
    public function validatePasswordLdap($attribute, $params)
    {
        if (!$this->hasErrors()) {
            $user = $this->getUserLdap();
            if (!$user || !Yii::$app->ldap->authenticate($this->username,$this->password)) {
                $this->addError($attribute, 'Incorrect username or passwords.');
            }
        }
    }
    
    public function loginLdap()
    {
        if ($this->validate()) {
            return Yii::$app->user->login($this->getUserLdap(), $this->rememberMe ? 3600 * 24 * 30 : 0);
        } else {
            return false;
        }
    }
    

    用户.php

    public static function findIdentity($id)
    {
    
        $new_identity = new User();
    
        if ($user_ldap_info = Yii::$app->ldap->user()->infoCollection($id, array("*"))){
            $new_identity->setId($user_ldap_info->samaccountname);
            $new_identity->setEmail($user_ldap_info->mail);
            $new_identity->setUsername($user_ldap_info->displayName);   
        }
    
        return $new_identity;
    }
    
    public function setEmail($email)
    {
        $this->email = $email;
    }
    
    public function setUsername($username)
    {
        $this->username = $username;
    }
    
    public function setId($id)
    {
        $this->id = $id;
    }
    

    在 LoginForm.php 中

    public function getUserLdap()
    {
        if ($this->_user === false) {           
            $this->_user = User::findIdentity($this->username);
        }
    
        return $this->_user;
    }
    

    编辑:由于供应商 ADLDAP 更新,我不得不将 findIdentity 更改为:

    public static function findIdentity($id)
    {
        $new_identity = new User ();
    
        if ( $user_ldap_info = Yii::$app->ldap->users()->find($id) ) {
            $new_identity->setId ( $user_ldap_info->samaccountname [0] );
            $new_identity->setEmail ( $user_ldap_info->mail[0] );
            $new_identity->setUsername ( $user_ldap_info->givenname [0] );
        }
    
        return $new_identity;
    }
    

    【讨论】:

    • 嗨,南,你好吗?我一直在尝试设置 ldap 身份验证,就像你一样。我也在使用 yii2-adldap-module 我无法让它工作。你是如何设置 getUserLdap 的?
    • 好的,我让它工作了。我修改了 amnah/yii-user 以获得混合解决方案。我想在 AD 上进行身份验证,但我也希望将用户存储在数据库中,因此我可以使用 RBAC 而不是 AD 组。最好让登录过程在 AD 上进行身份验证并验证用户是否已存在于数据库中。如果没有,请自动注册。如果我设法让它工作,我会尝试将它发布到某个地方。
    • 嗨丹尼尔!我还添加了此功能以防万一。就我而言,我不将用户保留在 DB 中,但我也考虑在 DB 用户管理中放置一些角色。
    • @Nan 函数 infoCollection() 位于哪个文件中?我收到一个错误调用未定义的方法 Adldap\Classes\AdldapUsers::infoCollection()
    • 我认为这是由于 ADldap 供应商更新,我不得不更改语法。我写一个更新
    【解决方案2】:

    我希望能找到 Daniel Stolf 发表了他所描述的工作示例。

    在搜索时,我想知道这是否已使用最新的 Larvel 5.1 完成并发现:

    https://libraries.io/github/sroutier/laravel-5.1-enterprise-starter-kit

    使用 sroutier/eloquent-ldap 的可选 LDAP/AD 身份验证,带有 选项:

    Automatically creates local account for LDAP/AD users on first login.
    Automatically assign to matching local roles based on LDAP/AD group membership.
    Refresh role assignment on login.
    

    这正是我一直在寻找的。我更喜欢使用 Yii2 框架,但由于 Yii2 缺乏这样的一体化扩展功能,我想我会转向 Laravel。

    除非 Konrad 为 Yii2 重写本指南: http://blog.realhe.ro/windows/yii-role-mapping-based-on-active-directory

    【讨论】:

    • 不幸的是,我最终将来自 Yii 的 RBAC 与自定义 LDAP 验证相结合。因此,当有人第一次登录时,LDAP 会验证并且 RBAC 在数据库中创建用户和角色。然后可以根据需要修改此角色。我第一次从用户的 ldap 组中扮演一些角色。
    【解决方案3】:

    先声明一下:贴出的代码 sn-ps 都是基本的例子。您需要自己处理琐碎的异常和进一步的逻辑。


    我将发布一个快速破解,以使用 Yii2 高级模板实现简单的 AD 身份验证,该模板将采用用户名/密码并针对 MS Active Directory 域控制器验证此组合。此外,它还会检查用户给定的组成员身份,因此只有该组的用户才能登录。

    我们假设:

    • 用户(特别是用户名)必须存在于当前 用户表(查看Authorization Guide 以构建 rbac 结构)。我们进一步假设我们数据库中的 用户名 与您要针对 AD 进行身份验证的用户名相同。
    • 您已为 Yii2 正确设置了 Adldap2 包装器(如 alexeevdv/yii2-adldap)或将 Adladp2 作为供应商模块加载。 从包装器中受益:您可以在应用程序配置的组件部分配置 adldap2 类,然后您可以将包装器用作 Yii2 组件。
    • 您的 PHP 环境使用 LDAP 扩展(例如,在 debian 发行版上运行 apt-get install php5-ldap 之类的东西)。
    • 您有一些管理员凭据可以连接到域控制器,并有权以您想要的方式查询 AD。

    那么,让我们从基本设置开始吧。

    设置包装器配置(例如 config/main-local.php)。

    'components' => [
        'ldap' => [
            'class' => 'alexeevdv\adldap\Adldap',
            'options' => [
                'account_suffix' => '@stackoverflow.com',
                'domain_controllers' => ['dc1.stackoverflow.com', 'dc2.stackoverflow.com'],
                'base_dn' => 'dc=stackoverflow,dc=com',
                'admin_username' => 'someusername',
                'admin_password' => 'somepassword',
                'use_ssl' => true,
                'port' => '636'
            ],
        ],
    ],
    

    我想在 ldap 和本地身份验证之间轻松切换。配置一些本地参数以具有全局可访问的应用程序参数(例如 config/params-local.php)。

    return [
        'adminEmail' => 'admin@example.com',
        'authOverLdap' => true,
        'ldapGroup' => 'someldapgroup',
    ];
    

    编辑您的 LoginForm.php,尤其是 validatePassword 函数(例如 common/models/LoginForm.php)。

    /**
     * Validates the password.
     * This method serves as the inline validation for password.
     * If the authOverLdap attribute is set in the params config,
     * user and password will be authenticated over ldap
     *
     * @param string $attribute the attribute currently being validated
     * @param array $params the additional name-value pairs given in the rule
     */
    public function validatePassword($attribute, $params)
    {
        if (!$this->hasErrors()) {
            $user = $this->getUser();
            // to switch between the auth-methods
            $authOverLdap = \Yii::$app->params['authOverLdap'];
            if ($authOverLdap) {
                if (!$user || !$user->validateCredentialsOverLdap($user->username, $this->password)) {
                    $this->addError($attribute, 'Some error text.');
                }
            } else {
                if (!$user || !$user->validatePassword($this->password)) {
                    $this->addError($attribute, 'Some error text.');
                }
            }
        }
    }
    

    在处理 LDAP 身份验证的用户模型中添加 validateCredentialsOverLdap 函数(例如 /common/models/User.php)。

    /**
     * Validates a user/password combination over ldap
     *
     * @param string $username username to validate over ldap
     * @param string $password password to validate over ldap
     * @return boolean if the provided credentials are correct and the user is a member of **ldapGroup**
     */
    public function validateCredentialsOverLdap($username, $password)
    {
        $authSuccess = false;
        // checking the supplied credentials against the ldap (e.g. Active Directory)
        // first step: the user must have a valid account
        // second step: the user must be in a special group
        $authOk = \Yii::$app->ldap->authenticate($username, $password);
        if ($authOk) {
            $adUser = \Yii::$app->ldap->users()->find($username);
            // the user must be in special group (set in Yii params)
            if($adUser->inGroup(\Yii::$app->params['ldapGroup'])) {
                $authSuccess = true;
            }
        }
    
        return $authSuccess;
    }
    

    免责声明:

    • 不要复制和粘贴这些 sn-ps!你必须知道你在做什么!
    • 这将向您展示一个示例,并为您提供使用包装器和 Yii2 框架实现 AD 身份验证的提示。
    • 我在围墙花园中运行此代码内联网
    • 使用永远SSL这样的安全层通过LDAP进行通信!您不知道谁在嗅探您可能安全网络中的流量。您处理用户凭据。这可能是个大问题,尤其是在单点登录环境中!别傻了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-21
      • 2011-01-12
      相关资源
      最近更新 更多