Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
602 views
in Technique[技术] by (71.8m points)

authentication - CakePHP Auth Component Using 2 Tables

CakePHP Version 1.2.5

I would like a single user to have multiple email addresses.
I would like a single user to have a single password.
I would like users to log in using any of their multiple email addresses and their single password.

I have created a users table with an id and a password field.
I have created a user_email_addresses table with an id field a user_id field and an email_address field.

Question:
How do I modify the auth component minimally to look for the "username" in this case, "email_address", in the user_email_addresses table and the "password" in the users table?

Seems as though modifying the identify method in the auth component might do it. But I think modifying the auth component directly is a bad idea - any ideas on how to extend and still possibly modify the identify method? http://cakebaker.42dh.com/2009/09/08/extending-cakephps-core-components/ or possibly nominate a different authenticate object?

Starting line 774:

    function identify($user = null, $conditions = null) {
    if ($conditions === false) {
        $conditions = null;
    } elseif (is_array($conditions)) {
        $conditions = array_merge((array)$this->userScope, $conditions);
    } else {
        $conditions = $this->userScope;
    }
    if (empty($user)) {
        $user = $this->user();
        if (empty($user)) {
            return null;
        }
    } elseif (is_object($user) && is_a($user, 'Model')) {
        if (!$user->exists()) {
            return null;
        }
        $user = $user->read();
        $user = $user[$this->userModel];
    } elseif (is_array($user) && isset($user[$this->userModel])) {
        $user = $user[$this->userModel];
    }

    if (is_array($user) && (isset($user[$this->fields['username']]) || isset($user[$this->userModel . '.' . $this->fields['username']]))) {

        if (isset($user[$this->fields['username']]) && !empty($user[$this->fields['username']])  && !empty($user[$this->fields['password']])) {
            if (trim($user[$this->fields['username']]) == '=' || trim($user[$this->fields['password']]) == '=') {
                return false;
            }
            $find = array(
                $this->userModel.'.'.$this->fields['username'] => $user[$this->fields['username']],
                $this->userModel.'.'.$this->fields['password'] => $user[$this->fields['password']]
            );
        } elseif (isset($user[$this->userModel . '.' . $this->fields['username']]) && !empty($user[$this->userModel . '.' . $this->fields['username']])) {
            if (trim($user[$this->userModel . '.' . $this->fields['username']]) == '=' || trim($user[$this->userModel . '.' . $this->fields['password']]) == '=') {
                return false;
            }
            $find = array(
                $this->userModel.'.'.$this->fields['username'] => $user[$this->userModel . '.' . $this->fields['username']],
                $this->userModel.'.'.$this->fields['password'] => $user[$this->userModel . '.' . $this->fields['password']]
            );
        } else {
            return false;
        }
        $model =& $this->getModel();
        $data = $model->find(array_merge($find, $conditions), null, null, 0);
        if (empty($data) || empty($data[$this->userModel])) {
            return null;
        }
    } elseif (!empty($user) && is_string($user)) {
        $model =& $this->getModel();
        $data = $model->find(array_merge(array($model->escapeField() => $user), $conditions));

        if (empty($data) || empty($data[$this->userModel])) {
            return null;
        }
    }

    if (!empty($data)) {
        if (!empty($data[$this->userModel][$this->fields['password']])) {
            unset($data[$this->userModel][$this->fields['password']]);
        }
        return $data[$this->userModel];
    }
    return null;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

AuthComponent::identify() takes two parameters, $user and $conditions

if ($conditions === false) {
        $conditions = null;
} elseif (is_array($conditions)) {
        $conditions = array_merge((array)$this->userScope, $conditions);
} else {
        $conditions = $this->userScope;
}

Looking at the above snippet, if you pass false as the $conditions, the method will execute with no model conditions.

Also, looking at the rest of the code, if you pass a $user value of type string, it won't execute most of the user-related code until it gets here:

} elseif (!empty($user) && is_string($user)) {
        $model =& $this->getModel();
        $data = $model->find(array_merge(array($model->escapeField() => $user), $conditions));

        if (empty($data) || empty($data[$this->userModel])) {
                return null;
        }
}

Here it runs Model::escapeField(), with no parameters, which returns an escaped version of User.id (by default) and maps this field to the string that was passed in. It then merges this with the $conditions array and performs a Model::find().

It should be safe to say that if the string is the user's ID and there are no conditions it will find the person with that ID every time.

As such, you should be able to extend AuthComponent to do what you want like so:

// app/controllers/components/app_auth.php
<?php
App::import('Component', 'Auth');
class AppAuthComponent extends AuthComponent {
/**
 * Custom user identification
 */
    function identify($user=null, $conditions=null) {
        // get the model AuthComponent is configured to use
        $model =& $this->getModel(); // default is User
        // do a query that will find a User record when given successful login data
        $user = $model->find('first', array('conditions' => array(
            'EmailAddress.' . $this->fields['username'] => $user[$this->userModel][$this->fields['username']],
            'User.' . $this->fields['password'] => $user[$this->userModel][$this->fields['password']],
        ));
        // return null if user invalid
        if (!$user) {
            return null; // this is what AuthComponent::identify would return on failure
        }
        // call original AuthComponent::identify with string for $user and false for $conditions
        return parent::identify($user[$this->userModel][$model->primaryKey], false);
    }
}
?>

You will have to replace all references to Auth with AppAuth in your application unless you follow this handy tip (the approach in the comments is nice).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...