2016-07-15 16:15:15 4474次浏览 3条回答 2 悬赏 500 金钱

我使用的Yii2 basic 2.0.9。登录使用的基础模板的登录,我修改了models\LoginForm.php中的login(),登录的用户资料是从API中请求过来的。因为在site/login()中登录成功之后var_dump(Yii::$app->user);,输出的结果有API返回的user资料,调到site/index之后,再输出var_dump(Yii::$app->user);输出的结果没有user的资料。百度和谷歌之后,很多登录案例是使用db的。

我的问题是:我应该如何正确保存API返回的用户信息保存到session中,在其它页面var_dump(Yii::$app->user);输出也能输出用户资料。

models\LoginForm.phplogin()方法。

/**
 * Logs in a user using the provided username and password.
 * @return boolean whether the user is logged in successfully
 */
public function login()
{
    if ($this->validate()) {
        //return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
        try{
            //GuzzleHttp\Client
            $client = new Client(['base_url'=>API_HOST.API_HOST_POSTFIX]);
            $response = $client->get('wp-api-registration/v2/registration',[
                'query'=>['username'=>$this->username,'password'=>$this->password]
            ]);
            $result = $response->json();
            $this->_user = User::getUserIdentity($result);
            return Yii::$app->user->login($this->_user);
        }catch (RequestException $e){
            //当不正确的时候
            if ($e->hasResponse() && $e->getCode() == 400) {
                $responseBody = json_decode($e->getResponse()->getBody());
                if($responseBody->code == 'json_login_error'){
                    $this->addError('username', '用戶名或者密碼不正確.');
                }
            }else{
                echo $e->getResponse();
            }
        }

    }
    return false;
}

models\User.php类:

<?php

namespace app\models;

class User extends \yii\base\Object implements \yii\web\IdentityInterface
{
    public $id;
    public $name;
    public $first_name;
    public $last_name;
    public $email;
    public $url;
    public $description;
    public $link;
    public $nickname;
    public $slug;
    public $registered_date;
    public $roles;
    public $capabilities;
    public $extra_capabilities;
    public $username;
    public $password;
    public $authKey;
    public $accessToken;

    public static function getUserIdentity($data){
        return new static($data);
    }

    /**
     * @inheritdoc
     */
    public static function findIdentity($id)
    {

    }

    /**
     * @inheritdoc
     */
    public static function findIdentityByAccessToken($token, $type = null)
    {

    }

    /**
     * Finds user by username
     *
     * @param string $username
     * @return static|null
     */
    public static function findByUsername($username)
    {

    }


    /**
     * @inheritdoc
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @inheritdoc
     */
    public function getAuthKey()
    {

    }

    /**
     * @inheritdoc
     */
    public function validateAuthKey($authKey)
    {

    }

}

API返回结果是:



    {
        "id": 1,
        "username": "admin",
        "name": "admin",
        "first_name": "",
        "last_name": "",
        "email": "test@test.com",
        "url": "",
        "description": "",
        "link": "http://192.168.1.119/wordpress/blog/author/admin/",
        "nickname": "admin",
        "slug": "admin",
        "registered_date": "2016-06-25T02:31:45+00:00",
        "roles":
        [
            "administrator"
        ],
        "capabilities":
        {
            "switch_themes": true,
            "edit_themes": true,
            "activate_plugins": true,
            "edit_plugins": true,
            "edit_users": true,
            "edit_files": true,
            "manage_options": true,
            "moderate_comments": true,
            "manage_categories": true,
            "manage_links": true,
            "upload_files": true,
            "import": true,
            "unfiltered_html": true,
            "edit_posts": true,
            "edit_others_posts": true,
            "edit_published_posts": true,
            "publish_posts": true,
            "edit_pages": true,
            "read": true,
            "level_10": true,
            "level_9": true,
            "level_8": true,
            "level_7": true,
            "level_6": true,
            "level_5": true,
            "level_4": true,
            "level_3": true,
            "level_2": true,
            "level_1": true,
            "level_0": true,
            "edit_others_pages": true,
            "edit_published_pages": true,
            "publish_pages": true,
            "delete_pages": true,
            "delete_others_pages": true,
            "delete_published_pages": true,
            "delete_posts": true,
            "delete_others_posts": true,
            "delete_published_posts": true,
            "delete_private_posts": true,
            "edit_private_posts": true,
            "read_private_posts": true,
            "delete_private_pages": true,
            "edit_private_pages": true,
            "read_private_pages": true,
            "delete_users": true,
            "create_users": true,
            "unfiltered_upload": true,
            "edit_dashboard": true,
            "update_plugins": true,
            "delete_plugins": true,
            "install_plugins": true,
            "update_themes": true,
            "install_themes": true,
            "update_core": true,
            "list_users": true,
            "remove_users": true,
            "promote_users": true,
            "edit_theme_options": true,
            "delete_themes": true,
            "export": true,
            "administrator": true
        },
        "extra_capabilities":
        {
            "administrator": true
        }
    }

最佳答案

  • wwwyii 发布于 2016-07-15 16:36 举报

    你的User需要实现findIdentity($id)这个函数,返回一个User实例。
    Yii里面的登录逻辑是这样的:在密码校验通过后,会调用Yii::$app->getUser->login($identify,$duration)来保存登录的用户的信息;以便下次访问直接获取用户的信息,不要再次输入密码等信息。
    问题1:如何保存用户的信息(/site/login)
    当然是保存到session和cookie中,这里和配置信息有关。yii\web\User.php中有两个参数$enableAutoLogin, $enableSession;
    $enableSession将用户信息保存在session中, $enableAutoLogin将信息进一步保存到cookie中,参考login的一段代码

        if ($identity) {
                $session->set($this->idParam, $identity->getId());
                if ($this->authTimeout !== null) {
                    $session->set($this->authTimeoutParam, time() + $this->authTimeout);
                }
                if ($this->absoluteAuthTimeout !== null) {
                    $session->set($this->absoluteAuthTimeoutParam, time() + $this->absoluteAuthTimeout);
                }
                if ($duration > 0 && $this->enableAutoLogin) {
                    $this->sendIdentityCookie($identity, $duration);
                }
    

    问题2, 用户下次访问的时候,如何获取用户的信息(访问/site/index)
    既然在问题1中保存到了session/cookie中,那么自然要从这个里面取出来。我们访问用户的信息的时候一般采用的方式是Yii::$app->getUser->getIdentity(),这个函数的功能就是从session/cookie中取出用户的数据并重构identiy实例。其中重构的关键代码如下,里面的 $class::findIdentity($id)使用来重新构建identity实例的,你的User恰好没有实现这个,所以导致啥也没有啊。

       protected function renewAuthStatus()
        {
            $session = Yii::$app->getSession();
            $id = $session->getHasSessionId() || $session->getIsActive() ? $session->get($this->idParam) : null;
    
            if ($id === null) {
                $identity = null;
            } else {
                /* @var $class IdentityInterface */
                $class = $this->identityClass;
              **_  $identity = $class::findIdentity($id);_**
            }
    
            $this->setIdentity($identity);
    
    2 条回复
    回复于 2016-07-15 16:48 回复

    原先models\User.php中有

    private static $users = [
            '100' => [
                'id' => '100',
                'username' => 'admin',
                'password' => 'admin',
                'authKey' => 'test100key',
                'accessToken' => '100-token',
            ],
            '101' => [
                'id' => '101',
                'username' => 'demo',
                'password' => 'demo',
                'authKey' => 'test101key',
                'accessToken' => '101-token',
            ],
        ];
    

    我将登录需要IdentityInterface 使用

    public static function getUserIdentity($data){
            self::$users = [];
            self::$users[$data['id']] = $data;
            return new static(self::$users[$data['id']]);
        }
    

    site/login登录成功之后,我获取到Yii::$app->user->isGuest为false,但是返回到首页site/index之后,Yii::$app->user->isGuest 是true。

    回复于 2016-07-15 17:18 回复

    谢谢,根据用户Id请求API,返回结果,提供了我一些思路。我可以将返回结果存在Session中,然后在findIdentity($id)中取出Session返回结果即可,我个人觉得存入Session是一个正确的方式。

    我的代码是:
    models\User.php中的findIdentity($id)方法

    /**
         * @inheritdoc
         */
        public static function findIdentity($id)
        {
    
            $session = Yii::$app->session;
            if($session->has('api_userinfo')){
                return new static($session->get('api_userinfo'));
            }
        }
    

    models\LoginForm.phplogin()方法存入到session的部分代码

    $result = $response->json();
    $this->_user = User::getUserIdentity($result);
    //将API返回结果存入session
    $session = Yii::$app->session;
    $session->set('api_userinfo',$result);
    
    return Yii::$app->user->login($this->_user);
    
  • 回答于 2016-07-15 16:35 举报

    登录后,

    $id=Yii::$app->user->identity->id
    

    通过这个就可以获取到你用户模型的id了,然后通过User::findOne($id)就能获得你用户资料了,只是举例,原理就是这样哦~

    8 条回复
    回复于 2016-07-15 16:38 回复

    这样的话,登录的用户是从数据库中读取的。但是我的用户数据,是用API中获取的。只是我的项目数据交互只会使用API形式,不会连接数据库的。

    回复于 2016-07-15 16:45 回复

    如我前面的回答,你需要在User中实现findIdentity($id)这个函数,返回一个User实例。和是否使用数据库保存没有关系。
    我看你使用的client是通过username/password来获取信息的,但是yii\web\user仅在session/cookie中保存了id信息。你需要么让client提供一个接口,通过id获取用户数据,或者将username/password也保存到session里面,以便在findIdentiy的时候获取这两个值,通过client获取信息。

    回复于 2016-07-15 16:48 回复

    完全同意~

    回复于 2016-07-15 17:02 回复

    试了在findIdentity($id)中使用$id通过API获取用户信息,当用户登录之后,当用户每次刷新画面,就需要从API中获取一次用户信息。感觉这样对服务器有压力,请求次数多。我觉得这样虽然可行,但不合理。

    回复于 2016-07-15 17:15 回复


    缓存啊;第一次findIdentity的时候把用户的数据保存到cache中,下次进来的时候去缓存里面取呗

    
       $model = Yii::$app->cache->get("User:$id");
                if ($model === false) {
                    $model = Client::getUserById($id);
                    if ($model !== null) {
                        Yii::$app->cache->set(
                            "User:$id",
                            $model,
                            3600
                        );
                    }
    
                }
                return $model;
    
    回复于 2016-07-15 17:23 回复

    目前Yii2的cache我不了解,目前我只好将返回结果存到Session中,从Session中读取。

    回复于 2016-07-15 17:26 回复


    session也可以的,取决于并发用户量的大小。
    session用的是内存,当并发用户量比较大的时候,内存会消耗比较大,这个时候可以转用缓存代替。

    回复于 2016-07-15 17:35 回复

    嗯,原来是这样,谢谢.。👍

  • 回答于 2016-12-21 10:31 举报

    lz您好,我想问一下,是不是默认保存在cookie里面的,看源代码的话好像都有保存,可是我的session是空的。请问一下它默认的登陆机制是保存在哪的?

    1 条回复
    回复于 2016-12-22 11:03 回复

    “登陆机制”不是很明白,不知是否是指用户登录之后的用户信息,应该cookie和session都有保存,yii\web\User#login()

您需要登录后才可以回答。登录 | 立即注册
wakasann
副董事长

wakasann 广东中山

注册时间:2014-10-20
最后登录:2022-08-29
在线时长:129小时30分
  • 粉丝25
  • 金钱44850
  • 威望30
  • 积分46440

热门问题