如何在 CakePHP 3.9 中的 AuthComponent 中使用 MD5

问题描述

我正在迁移使用 CakePHP 1.2 开发的 Web 应用程序 我正在将其迁移到版本 3.9.4。数据库中的用户密码都是使用 MD5 散列的,但 3.9.4 版本使用 bcrypt 作为认散列器。我想使用 MD5,因此我可以使用 MD5 对用户进行身份验证。我已经完成了这个 article 并按照文章中的指导使用了 LegacyPasswordHasher 类,但它不起作用。这是我在 AppController 中配置 AuthComponent 的方法

$this->loadComponent('Auth',[
            'authenticate' => ['Form' => [
                'passwordHasher' => [
                    'className' => 'Legacy',],'fields' => [
                    'username' => 'email','password' => 'password',]],'loginAction' => [
                'controller' => 'Users','action' => 'login',]);

这是我的 LegcayPasswordHasher 类:

<?PHP

namespace App\Auth;

use Cake\Auth\AbstractPasswordHasher;

class LegacyPasswordHasher extends AbstractPasswordHasher {
    public function hash($password) {
        return md5($password);
    }

    public function check($password,$hashedPassword) {
        $userPassword = md5($password);
        return $userPassword === $hashedPassword;
    }
}

这是旧系统中的 UserAuthComponent。位于app/Controller/Component

class UserAuthComponent extends Component {
    /**
     * This component uses following components
     *
     * @var array
     */
    var $components = array('Session','Cookie','RequestHandler','ControllerList');
    /**
     * configur key
     *
     * @var string
     */
    var $configureKey='User';

    function initialize(Controller $controller) {

    }

    function __construct(ComponentCollection $collection,$settings = array()) {
        parent::__construct($collection,$settings);
    }

    function startup(Controller $controller = null) {

    }
    /**
     * Called before the controller action.  You can use this method to configure and customize components
     * or perform logic that needs to happen before each controller action.
     *
     * @param object $c current controller object
     * @return void
     */
    function beforeFilter(&$c) {
        Usermgm@R_404_6193@t($this);
        $user = $this->__getActiveUser();
        $pageRedirect = $c->Session->read('permission_error_redirect');
        $c->Session->delete('permission_error_redirect');
        $controller = $c->params['controller'];
        $action = $c->params['action'];
        $actionUrl = $controller.'/'.$action;
        $requested= (isset($c->params['requested']) && $c->params['requested']==1) ? true : false;
        $permissionFree=array('users/login','users/logout','users/register','users/userVerification','users/forgotPassword','users/activatePassword','pages/display','users/accessDenied','users/emailVerification','users/admin_login','schools/garminApi','schools/viewActivitymy','schools/viewbonuspointupdate','students/viewclassstudentleader','students/viewclassstudentleaderexport','schools/viewpointsupdate');
        $access =str_replace(' ','',ucwords(str_replace('_',' ',$controller))).'/'.$action;
        $allControllers=$this->ControllerList->getControllerWithMethods();
        $errorPage=false;
        if (!in_array($access,$allControllers)) {
            $errorPage=true;
        }
        if(  $action == "viewActivitymy" || $action == "viewActivitymycron" || $action == "viewActivitymycronfitbit"|| $action == "viewActivityfitbit" || $action=="viewPointactivity" || $action =="viewActivitymycron_manual" || $action =="viewbonuspointupdate" || $action =="viewpointsupdate" || $action =="viewclassstudentleader" || $action =="viewclassstudentleaderexport"){
            
        }else{
        if ((empty($pageRedirect) || $actionUrl!='users/login') && !$requested && !in_array($actionUrl,$permissionFree) && !$errorPage) {
            App::import("Model","UserGroup");
            $userGroupModel = new UserGroup;
            if (!$this->isLogged()) {
                if (!$userGroupModel->isGuestAccess($controller,$action)) {
                    $c->log('permission: actionUrl-'.$actionUrl,LOG_DEBUG);
                    $c->Session->write('permission_error_redirect','/users/login');
                    $c->Session->setFlash('You need to be signed in to view this page.');
                    $cUrl = '/'.$c->params->url;
                    if(!empty($_SERVER['QUERY_STRING'])) {
                        $rUrl = $_SERVER['REQUEST_URI'];
                        $pos =strpos($rUrl,$cUrl);
                        $cUrl=substr($rUrl,$pos,strlen($rUrl));
                    }
                    $c->Session->write('OriginAfterLogin',$cUrl);
                    $c->redirect('/login');
                }
            } else {
                if (!$userGroupModel->isUserGroupAccess($controller,$action,$this->getGroupId())) {
                    $c->log('permission: actionUrl-'.$actionUrl,'/users/login');
                     $c->redirect('/accessDenied');
                }
            }
        }
        }
    }
    /**
     * Used to check whether user is logged in or not
     *
     * @access public
     * @return boolean
     */
    public function isLogged() {
        return ($this->getUserId() !== null);
    }
    /**
     * Used to get user from session
     *
     * @access public
     * @return array
     */
    public function getUser() {
        return $this->Session->read('UserAuth');
    }
    /**
     * Used to get user id from session
     *
     * @access public
     * @return integer
     */
    public function getUserId() {
        return $this->Session->read('UserAuth.User.id');
    }
    /**
     * Used to get group id from session
     *
     * @access public
     * @return integer
     */
    public function getGroupId() {
        return $this->Session->read('UserAuth.User.user_group_id');
    }
    /**
     * Used to get group name from session
     *
     * @access public
     * @return string
     */
    public function getGroupName() {
        return $this->Session->read('UserAuth.UserGroup.name');
    }
    /**
     * Used to check is admin logged in
     *
     * @access public
     * @return string
     */
    public function isAdmin() {
        $groupId = $this->Session->read('UserAuth.User.user_group_id');
        if($groupId==ADMIN_GROUP_ID) {
            return true;
        }
        return false;
    }
    /**
     * Used to check is guest logged in
     *
     * @access public
     * @return string
     */
    public function isGuest() {
        $groupId = $this->Session->read('UserAuth.User.user_group_id');
        if(empty($groupId)) {
            return true;
        }
        return false;
    }
    /**
     * Used to make password in hash format
     *
     * @access public
     * @param string $pass password of user
     * @return hash
     */
    public function makePassword($pass,$salt=null) {
        return md5(md5($pass).md5($salt));
    }
    /**
     * Used to make salt in hash format
     *
     * @access public
     * @return hash
     */
    public function makeSalt() {
        $rand = mt_rand(0,32);
        $salt = md5($rand . time());
        return $salt;
    }
    /**
     * Used to maintain login session of user
     *
     * @access public
     * @param mixed $type possible values 'guest','cookie',user array
     * @param string $credentials credentials of cookie,default null
     * @return array
     */
    public function login($type = 'guest',$credentials = null) {
        $user=array();
        if (is_string($type) && ($type=='guest' || $type=='cookie')) {
            App::import("Model","User");
            $usermodel = new User;
            $user = $usermodel->authsomeLogin($type,$credentials);
        } elseif (is_array($type)) {
            $user =$type;
        }
        Configure::write($this->configureKey,$user);
        $this->Session->write('UserAuth',$user);
        return $user;
    }
    /**
     * Used to delete user session and cookie
     *
     * @access public
     * @return void
     */
    public function logout() {
        $this->Session->delete('UserAuth');
        Configure::write($this->configureKey,array());
        $this->Cookie->delete(LOGIN_COOKIE_NAME);
    }
    /**
     * Used to persist cookie for remember me functionality
     *
     * @access public
     * @param string $duration duration of cookie life time on user's machine
     * @return boolean
     */
    public function persist($duration = '2 weeks') {
        App::import("Model","User");
        $usermodel = new User;
        $token = $usermodel->authsomePersist($this->getUserId(),$duration);
        $token = $token.':'.$duration;
        return $this->Cookie->write(
            LOGIN_COOKIE_NAME,$token,true,// encrypt = true
            $duration
        );
    }
    /**
     * Used to check user's session if user's session is not available then it tries to get login from cookie if it exist
     *
     * @access private
     * @return array
     */
    private function __getActiveUser() {
        $user = Configure::read($this->configureKey);
        if (!empty($user)) {
            return $user;
        }

        $this->__useSession() || $this->__useCookietoken() || $this->__useGuestAccount();

        $user = Configure::read($this->configureKey);
        if (is_null($user)) {
            throw new Exception(
                'Unable to initilize user'
            );
        }
        return $user;
    }
    /**
     * Used to get user from session
     *
     * @access private
     * @return boolean
     */
    private function __useSession() {
        $user = $this->getUser();
        if (!$user) {
            return false;
        }
        Configure::write($this->configureKey,$user);
        return true;
    }
    /**
     * Used to get login from cookie
     *
     * @access private
     * @return boolean
     */
    private function __useCookietoken() {
        $token = $this->Cookie->read(LOGIN_COOKIE_NAME);
        if (!$token) {
            return false;
        }
        $user=false;
        // Extract the duration appendix from the token
        if(strpos($token,":") !==false) {
            $tokenParts = split(':',$token);
            $duration = array_pop($tokenParts);
            $token = join(':',$tokenParts);
            $user = $this->login('cookie',compact('token','duration'));
            // Delete the cookie once its been used
        }
        $this->Cookie->delete(LOGIN_COOKIE_NAME);
        if (!$user) {
            return;
        }
        $this->persist($duration);
        return (bool)$user;
    }
    /**
     * Used to get login as guest
     *
     * @access private
     * @return array
     */
    private function __useGuestAccount() {
        return $this->login('guest');
    }
}

这是位于旧代码库中 User 处的 app/Mode/ 模型。

App::uses('AppModel','Model');
App::uses('CakeEmail','Network/Email');

class User extends AppModel {

    /**
     * This model belongs to following models
     *
     * @var array
     */
    var $belongsTo = array('UserGroup');
    /**
     * This model has following models
     *
     * @var array
     */
    var $hasMany = array('LoginToken'=>array('className'=>'LoginToken','limit' =>1));
    /**
     * model validation array
     *
     * @var array
     */
    var $validate = array();
    /**
     * UsetAuth component object
     *
     * @var object
     */
    var $userAuth;
    /**
     * model validation array
     *
     * @var array
     */
    function LoginValidate() {
        $validate1 = array(
                'email'=> array(
                    'mustNotEmpty'=>array(
                        'rule' => 'notEmpty','message'=> 'Please enter email or username')
                    ),'password'=>array(
                    'mustNotEmpty'=>array(
                        'rule' => 'notEmpty','message'=> 'Please enter password')
                    )
            );
        $this->validate=$validate1;
        return $this->validates();
    }
    /**
     * model validation array
     *
     * @var array
     */
    function RegisterValidate() {
        $validate1 = array(
                //"user_group_id" => array(
                    //'rule' => array('comparison','!=',0),//'message'=> 'Please select group'),'school_name'=> array(
                    'mustNotEmpty'=>array(
                        'rule' => 'notEmpty','message'=> 'Please enter school name','last'=>true),'mustUnique'=>array(
                        'rule' =>'isUnique','message' =>'This school name already taken',// 'mustBeLonger'=>array(
                    //  'rule' => array('minLength',4),//  'message'=> 'Username must be greater than 3 characters',//  'last'=>true),),'first_name'=> array(
                    'mustNotEmpty'=>array(
                        'rule' => 'notEmpty','message'=> 'Please enter administrator first name')
                    ),'last_name'=> array(
                    'mustNotEmpty'=>array(
                        'rule' => 'notEmpty','on' => 'create','message'=> 'Please enter administrator last name')
                    ),'email'=> array(
                    'mustNotEmpty'=>array(
                        'rule' => 'notEmpty','message'=> 'Please enter email','mustBeEmail'=> array(
                        'rule' => array('email'),'message' => 'Please enter valid email','message' =>'This email is already registered',)
                    ),'oldpassword'=>array(
                    'mustNotEmpty'=>array(
                        'rule' => 'notEmpty','message'=> 'Please enter old password','mustMatch'=>array(
                        'rule' => array('verifyOldPass'),'message' => 'Please enter correct old password'),'message'=> 'Please enter password','mustBeLonger'=>array(
                        'rule' => array('minLength',6),'message'=> 'Password must be greater than 5 characters','mustMatch'=>array(
                        'rule' => array('verifies'),'message' => 'Both passwords must match'),//'on' => 'create'
                    ),'number_of_student'=> array(
                    'mustNotEmpty'=>array(
                        'rule' => 'notEmpty','message'=> 'Please enter number of student')
                    ),'tracker'=> array(
                    'mustNotEmpty'=>array(
                        'rule' => 'notEmpty','message'=> 'Please enter tracker number')
                    ),'captcha'=>array(
                    'mustMatch'=>array(
                        'rule' => array('recaptchaValidate'),'message' => ''),)
            );
        $this->validate=$validate1;
        return $this->validates();
    }
    /**
     * Used to validate captcha
     *
     * @access public
     * @return boolean
     */
    public function recaptchaValidate() {
        App::import("vendor","recaptcha/recaptchalib");
        $recaptcha_challenge_field = (isset($_POST['recaptcha_challenge_field'])) ? $_POST['recaptcha_challenge_field'] : "";
        $recaptcha_response_field = (isset($_POST['recaptcha_response_field'])) ? $_POST['recaptcha_response_field'] : "";
        $resp = recaptcha_check_answer(PRIVATE_KEY_FROM_RECAPTCHA,$_SERVER['REMOTE_ADDR'],$recaptcha_challenge_field,$recaptcha_response_field);
        $error = $resp->error;
        if(!$resp->is_valid) {
            $this->validationErrors['captcha'][0]=$error;
        }
        return true;
    }
    /**
     * Used to match passwords
     *
     * @access public
     * @return boolean
     */
    public function verifies() {
        return ($this->data['User']['password']===$this->data['User']['cpassword']);
    }
    /**
     * Used to match old password
     *
     * @access public
     * @return boolean
     */
    public function verifyOldPass() {
        $userId = $this->userAuth->getUserId();
        $user = $this->findById($userId);
        $oldpass=$this->userAuth->makePassword($this->data['User']['oldpassword'],$user['User']['salt']);
        return ($user['User']['password']===$oldpass);
    }
    /**
     * Used to send registration mail to user
     *
     * @access public
     * @param array $user user detail array
     * @return void
     */
    public function sendRegistrationMail($user) {
    
        // $user['User']['email'];
        // send email to newly created user
        $email = new CakeEmail();
        $userId=$user['User']['id'];
        $email->config('smtp');
        $fromConfig = '[email protected]';
        $fromNameConfig = 'Pradeep';
        $email->from(array( $fromConfig => $fromNameConfig));
        $email->sender(array( $fromConfig => $fromNameConfig));
        $email->to($user['User']['email']);
        $email->subject('Your registration is complete');
        //$email->transport('Debug');
        $body="Welcome ".$user['User']['first_name'].",Thank you for your registration on ".'http://localhost/garmin/register'." \n\n Thanks,\n".EMAIL_FROM_NAME;
        try{
            $result = $email->send($body);
        } catch (Exception $ex) {
            // we Could not send the email,ignore it
            $result="Could not send registration email to userid-".$userId;
        }
        $this->log($result,LOG_DEBUG);
    }
    /**
     * Used to send email verification mail to user
     *
     * @access public
     * @param array $user user detail array
     * @return void
     */
    public function sendVerificationMail($user) {
        $userId=$user['User']['id'];
        $email = new CakeEmail();
        $email->config('smtp');
        $fromConfig = '[email protected]';
        $fromNameConfig = 'Pradeep';
        $email->from(array( $fromConfig => $fromNameConfig));
        $email->sender(array( $fromConfig => $fromNameConfig));
        $email->to($user['User']['email']);
        $email->subject('Email Verification Mail');
        $activate_key = $this->getActivationKey($user['User']['password']);
        $link = Router::url("/userVerification?ident=$userId&activate=$activate_key",true);
        $body="Hi,Click the link below to complete your registration \n\n ".$link;
        try{
            $result = $email->send($body);
        } catch (Exception $ex){
            // we Could not send the email,ignore it
            $result="Could not send verification email to userid-".$userId;
        }
        $this->log($result,LOG_DEBUG);
    }
    /**
     * Used to generate activation key
     *
     * @access public
     * @param string $password user password
     * @return hash
     */
    public function getActivationKey($password) {
        $salt = Configure::read ( "Security.salt" );
        return md5(md5($password).$salt);
    }
    /**
     * Used to send forgot password mail to user
     *
     * @access public
     * @param array $user user detail
     * @return void
     */
    public function forgotPassword($user) {
        $userId=$user['User']['id'];
        $email = new CakeEmail();
        $fromConfig = EMAIL_FROM_ADDRESS;
        $fromNameConfig = EMAIL_FROM_NAME;
        $email->from(array( $fromConfig => $fromNameConfig));
        $email->sender(array( $fromConfig => $fromNameConfig));
        $email->to($user['User']['email']);
        $email->subject(EMAIL_FROM_NAME.': Request to Reset Your Password');
        $activate_key = $this->getActivationKey($user['User']['password']);
        $link = Router::url("/activatePassword?ident=$userId&activate=$activate_key",true);
        $body= "Welcome ".$user['User']['first_name'].",let's help you get signed in

You have requested to have your password reset on ".EMAIL_FROM_NAME.". Please click the link below to reset your password Now :

".$link."


If above link does not work please copy and paste the URL link (above) into your browser address bar to get to the Page to reset password

Choose a password you can remember and please keep it secure.

Thanks,\n".

EMAIL_FROM_NAME;
        try{
            $result = $email->send($body);
        } catch (Exception $ex){
            // we Could not send the email,ignore it
            $result="Could not send forgot password email to userid-".$userId;
        }
        $this->log($result,LOG_DEBUG);
    }
    /**
     * Used to mark cookie used
     *
     * @access public
     * @param string $type
     * @param string $credentials
     * @return array
     */
    public function authsomeLogin($type,$credentials = array()) {
        switch ($type) {
            case 'guest':
                // You can return any non-null value here,if you don't
                // have a guest account,just return an empty array
                return array();
            case 'cookie':
                $loginToken=false;
                if(strpos($credentials['token'],":") !==false) {
                    list($token,$userId) = split(':',$credentials['token']);
                    $duration = $credentials['duration'];

                    $loginToken = $this->LoginToken->find('first',array(
                        'conditions' => array(
                            'user_id' => $userId,'token' => $token,'duration' => $duration,'used' => false,'expires <=' => date('Y-m-d H:i:s',strtotime($duration)),'contain' => false
                    ));
                }
                if (!$loginToken) {
                    return false;
                }
                $loginToken['LoginToken']['used'] = true;
                $this->LoginToken->save($loginToken);

                $conditions = array(
                    'User.id' => $loginToken['LoginToken']['user_id']
                );
            break;
            default:
                return array();
        }
        return $this->find('first',compact('conditions'));
    }
    /**
     * Used to generate cookie token
     *
     * @access public
     * @param integer $userId user id
     * @param string $duration cookie persist life time
     * @return string
     */
    public function authsomePersist($userId,$duration) {
        $token = md5(uniqid(mt_rand(),true));
        $this->LoginToken->create(array(
            'user_id' => $userId,'expires' => date('Y-m-d H:i:s',));
        $this->LoginToken->save();
        return "${token}:${userId}";
    }
    /**
     * Used to get name by user id
     *
     * @access public
     * @param integer $userId user id
     * @return string
     */
    public function getNameById($userId) {
        $res = $this->findById($userId);
        $name=(!empty($res)) ? ($res['User']['first_name'].' '.$res['User']['last_name']) : '';
        return $name;
    }
    /**
     * Used to check users by group id
     *
     * @access public
     * @param integer $groupId user id
     * @return boolean
     */
    public function isUserAssociatedWithGroup($groupId) {
        $res = $this->find('count',array('conditions'=>array('User.user_group_id'=>$groupId)));
        if(!empty($res)) {
            return true;
        }
        return false;
    }
}

这是旧代码库中位于 app/Controller 处的 UserController

期待您的指导。提前致谢。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)