代码之家  ›  专栏  ›  技术社区  ›  Dev

用于会话ip地址不工作的移动设备的Yii2 rest Api

  •  2
  • Dev  · 技术社区  · 7 年前

    我已经开发了基于web的rest API,但这是我第一次为移动应用程序创建rest API。我正在尝试向用户发布的手机号码发送短信代码。SMS代码保存在具有用户ip地址的会话中。

    下一步,用户发送短信代码。Rest API比较会话中发布的SMS代码。

    以下是我发送短信和验证短信代码的代码:

     //send sms code here
     public function actionSendSms(){
       $this->response['success'] = false;
       $model = $this->loadPostData('step1phone');
       $phone = str_replace('+','',Yii::$app->request->post('phone'));
       $model->phone = urlencode(preg_replace('/[^\d\+]/', '', $phone));
       if(Yii::$app->request->isPost && $model->validate()){
         $code = Yii::$app->helper->generateRandomString(4);
         Yii::$app->sms->setMessage($code);
         $sms = Yii::$app->sms->send($model->phone);
         if($sms->status){
            $ipAddress = Yii::$app->request->getUserIP();
            Yii::$app->session->set('phone-'.$ipAddress, $code);
            $this->response['success'] = true;
        }else{
            $this->response['errorMessage'] = $sms->errorMessage;
        }
      }else{
        $this->response['status'] = 'error';
        $this->response['errors'] = $model->getErrors(); //@TODO
      }
      return $this->response;
    }
    //sms code validation here
    public function actionSendSmsCode()
    {
        $ipAddress = Yii::$app->request->getUserIP();
        \Yii::info('User IP - '.$ipAddress, 'mylog');
        $model = $this->loadPostData('step1phoneVerify');
        if($model->validate()){
          $this->response['status'] = true;
          $this->response['data'] = [
              'code' => Yii::$app->session->get('phone-'.$ipAddress),
              'postValue' => Yii::$app->request->post('phoneVerificationCode'),
          ];
            \Yii::info('code - '.Yii::$app->session->get('phone-'.$ipAddress), 'mylog');
            \Yii::info('postValue - '.Yii::$app->request->post('phoneVerificationCode'), 'mylog');
            \Yii::info('User IP - '.Yii::$app->request->getUserIP(), 'mylog');
        }
        else
        {
            $this->response['status'] = 'error';
            $this->response['error'] = $model->getErrors();
            $this->response['data'] = [
                'code' => Yii::$app->session->get('phone-'.Yii::$app->request->getUserIP()),
                'postValue' => Yii::$app->request->post('phoneVerificationCode'),
            ];
            \Yii::info('code - '.Yii::$app->session->get('phone-'.$ipAddress), 'mylog');
            \Yii::info('postValue - '.Yii::$app->request->post('phoneVerificationCode'), 'mylog');
            \Yii::info('User IP - '.Yii::$app->request->getUserIP(), 'mylog');
        }
        \Yii::info('Session - '. json_encode(Yii::$app->session) , 'mylog');
        //$this->$this->response['session'] = Yii::$app->session->get('phone-'.$ipAddress);
        return $this->response;
    }
    
    //Model used for validation.
    public function validateSmsCode($attribute, $params)
    {
        $ipAddress = Yii::$app->request->getUserIP();
        if(!empty($this->phoneVerificationCode) && $this->phoneVerificationCode != Yii::$app->session->get('phone-'.$ipAddress))
        {
            $this->addError('phoneVerificationCode', Yii::t('app', 'SMS code doesn`t match.'));
        }
    }
    

    当我尝试从post Rest API服务测试代码时,一切正常。 但从移动应用程序中,即使我发布了正确的短信代码,也无法得到验证。

    当我尝试在日志文件中查看时。“code-”为空,但“User IP-”获取用户的IP地址。

    在这里,如果我使用post rest API服务,我会在日志文件中获得例外信息。我的应用程序前端是Android。

    我做错了什么?

    1 回复  |  直到 3 年前
        1
  •  1
  •   Mohd Alomar    7 年前

    您的错误是,您使用IP地址作为安全和静态值,这是错误的。

    IP地址: 每个用户的用户IP地址不是唯一的,因为数量有限,所以通常多个用户共享相同的IP、NAT公共IP地址,请阅读有关NAT的更多信息,但请记住用户IP是共享的,可以更改,攻击者可以欺骗它。

    php会话: 通常存储在服务器上的数据(并非所有情况下都是这样)。因此,服务器将密钥作为安全令牌发送给客户端,并且每次客户端都会在cookie中发送此令牌,以便服务器可以加载会话。因此,您不需要IP—您已经拥有安全令牌。

    将数据保存到会话:

    Yii::$app->session->set('phone', $model->phone);
    Yii::$app->session->set('code', $code);
    //Just use key (static string) to store in session as this session in unique per user
    

    正在从会话读取数据:

    $phone = Yii::$app->session->get('phone');
    $code = Yii::$app->session->get('code');
    //Just use key that you used to store the data
    

    我建议阅读更多关于Yii2课程的信息 YII2 session guide

    请记住,您应该使用cookie在所有请求中发送会话id。此外,很少使用应用内开发会话,它们通常使用rest授权(如auth2和缓存)在服务器上存储数据。

    会话示例: 假设我们有这个代码

    public function actionPageCount(){
        if(Yii::$app->session->get('count'))
            Yii::$app->session->set('count',Yii::$app->session->get('count')+1);
        else
            Yii::$app->session->set('count',1);
    
        return Yii::$app->session->get('count');
    }
    

    用户第一次调用此操作时,if语句将为false,因为用户没有会话id,因此在else中,web应用将创建一个新会话,并将count设置为1。创建会话时,服务器将向浏览器或应用程序发送此标头。

    Set-Cookie: PHPSESSID=rl721ac6h3vfgld5repf8pcjl6; path=/; HttpOnly
    

    这意味着创建名为PHPSESSID的新cookie,其值为rl721ac6h3vfgld5repf8pcjl6。因此,当用户再次调用该操作时。服务器将根据会话id加载会话。如果用户没有包含会话id,服务器将创建新会话。从浏览器调用此方法并查看其行为,然后打开和新建专用选项卡并再次调用它,并查看服务器将为您管理会话。在应用程序中,您必须保存会话id并在每个请求中添加为cookie。