Javascript 验证Parse.com用户和会话服务器端

Javascript 验证Parse.com用户和会话服务器端,javascript,rest,parse-platform,Javascript,Rest,Parse Platform,我目前正在通过使用Parse Javascript SDK构建一些示例客户端应用程序来探索Parse平台。我决定将大部分与解析相关的逻辑从应用程序中抽象出来,并抽象到运行在VPS上的RESTful API中。其目的是使应用程序尽可能成为后端不可知论者 我构建的RESTful API只是一个使用Node.js解析包的Express.js应用程序 我的问题是:当我想向我的RESTAPI发出请求时,验证发出请求的用户的最佳方法是什么 例如:考虑一个用户可以拥有朋友的应用程序: 用户使用Parse.Us

我目前正在通过使用Parse Javascript SDK构建一些示例客户端应用程序来探索Parse平台。我决定将大部分与解析相关的逻辑从应用程序中抽象出来,并抽象到运行在VPS上的RESTful API中。其目的是使应用程序尽可能成为后端不可知论者

我构建的RESTful API只是一个使用Node.js解析包的Express.js应用程序

我的问题是:当我想向我的RESTAPI发出请求时,验证发出请求的用户的最佳方法是什么

例如:考虑一个用户可以拥有朋友的应用程序:

  • 用户使用Parse.User.logIn()方法在客户端登录
  • 客户端在我的RESTAPI上点击端点/users/me/friends,它检查用户是否有有效会话,并返回用户的朋友列表
  • 因此,这需要服务器端解析代码来确定:

  • 提出请求的用户是谁,以及
  • 如果当前用户具有有效会话
  • 我考虑使用以下方法:

  • 当用户登录客户端时,他/她会收到一个会话令牌
  • 发出API请求时,将此会话令牌作为标头附加
  • 在服务器上,将此会话令牌与Parse.User.been()方法结合使用,以设置当前用户并执行所需的逻辑:
  • 因此,express应用程序将处理上述示例:
  • router.get(“/users/me/friends”),函数(req,res){
    var sessionToken=req.headers[“sessionToken”];
    Parse.User.been(sessionToken).then(函数(用户){
    /*有效用户和会话:查找并返回用户好友*/
    },函数(错误){
    /*无效:返回错误状态并返回错误*/
    });
    });
    

    这是处理这种情况的有效方法吗?如果我继续这样做,有什么问题需要注意吗?谢谢

    我一直在问自己同样的问题,我提出的解决方案与您所解释的非常相似。我正在开发一个android应用程序,它只对用户和会话片段使用Parse,其他所有内容都将是MySQL、Redis或我计划在将来包装的任何其他数据源。我已经使用PHP和Slim框架在VPS上开发了自己的RESTAPI。我利用了Parse中的身份验证部分,在我自己生成的users表中添加了一个ApiKey列,然后还利用了已经为每个用户创建和管理的SessionToken。当用户对我的web服务进行身份验证调用时,他们会在每个请求头中提供api密钥和会话令牌,当我的服务器接收到请求时,它会通过端部的解析验证apiKey+sessionToken对是否有效。每次用户重新登录时都会重新创建sessionToken,因此这在一定程度上保证了它的安全性。因此,目前我正在使用Parse Android SDK客户端和Parse PHP SDK服务器端。我已经能够使create user、login user和list user成为解析的端点。您提到的“成为”功能确实帮助我解决了用户将会话令牌发送到服务器并尝试验证它的问题,因为只有当前用户才能查看自己的会话信息。我在PHP文档中找不到任何关于它的内容,但显然它是可用的,您只需执行如下操作。如果你有任何想法或意见,你认为可以使这更好,我是开放的想法

    DBHandlerParse类摘录:

       /**
         * Validating user api key
         * If the api key is there in db, it is a valid key
         * @param String $api_key user api key
         * @return boolean
         */
        public function isValidApiKey($api_key) {
            $query = ParseUser::query();
            $query->equalTo("apiKey",$api_key);
            $results = $query->find();
    
            if(count($results) > 0){
                return true;
            } else{
                return false;
            }
        }
    
        /**
         * Validating user session token
         * If the session token matches the api key user, it is a valid token
         * @param String $session_token user session token
         * @param String $api_key user api key
         * @return boolean
         */
        public function isValidSessionToken($session_token, $api_key) {
    
            // Using already validated $api_key, obtain corresponding user object
            $query = ParseUser::query();
            $query->equalTo("apiKey",$api_key);
            $results = $query->find();
    
            if(count($results) > 0){
                $userObj = $results[0];
            } else{
                return FALSE;
            }
    
            try{
                // Become user that has this session token
                // Only way to query back the user that they are
                // If no user is found with this token, parse error
                $thisUser = ParseUser::become($session_token);
    
                $query = ParseSession::query();
                $query->equalTo("user", $userObj);
                $results = $query->find();
    
                if(count($results) > 0){
                    return TRUE;
                } else{
                    return FALSE;
                }
            } catch (Parse\ParseException $error){
                return FALSE;
            }
        }
    
    身份验证中间件:

    /**
     * Adding Middle Layer to authenticate every request
     * Checking if the request has valid api key in the 'Authorization' & 'Token' header
     */
    function authenticate(\Slim\Route $route) {
        // Getting request headers
        $headers = apache_request_headers();
        $response = array();
        $app = \Slim\Slim::getInstance();
    
        // Verifying Authorization Header
        if (isset($headers['Authorization']) && isset($headers['Token'])) {
            $db = new DbHandlerParse();
    
            // get the api key
            $api_key = $headers['Authorization'];
            // get the session token
            $session_token = $headers['Token'];
    
            // validating api key
            if (!$db->isValidApiKey($api_key)) {
                // api key is not present in users table
                $response["result"] = "error";
                $response["message"] = "Access Denied. Invalid Api key";
                echoRespnse(401, $response);
                $app->stop();
            } else if(!$db->isValidSessionToken($session_token, $api_key)) {
                // session token does not match api key or is just invalid
                $response["result"] = "error";
                $response["message"] = "Access Denied. Invalid Token";
                echoRespnse(401, $response);
                $app->stop();
            } else {
                global $user_id;
                // get user primary key id
                $userID = $db->getUserId($api_key);
                if (NULL != $userID)
                    $user_id = $userID;
            }
        } else if(!isset($headers['Authorization'])){
            // api key is missing in header
            $response["result"] = "error";
            $response["message"] = "Api key is misssing";
            echoRespnse(400, $response);
            $app->stop();
        } else {
            // token is missing in header
            $response["result"] = "error";
            $response["message"] = "Token is misssing";
            echoRespnse(400, $response);
            $app->stop();
        }
    }
    
    示例路线:

    /**
     * Users List
     * url - /list
     * method - GET
     */
    $app->get('/users/list', 'authenticate', function() use ($app) {
        $response = array();
    
        $db = new DbHandlerParse();
        $results = $db->getUserList();
        $records = array();
    
        //echo "Successfully retrieved " . count($results) . " scores.<br><br>";
        // Do something with the returned ParseObject values
        for ($i = 0; $i < count($results); $i++) {
            $object = $results[$i];
    
            $record = array();
            $records[$i]['userId'] = $object->getObjectId();
            $records[$i]['firstName'] = $object->get('firstName');
            $records[$i]['lastName'] = $object->get('lastName');
            $records[$i]['username'] = $object->get('username');
            $records[$i]['email'] = $object->get('email');
    
            //echo $object->getObjectId() . ' - ' . $object->get('username') . '<br>';
        }
    
        // check for records returned
        if ($records) {
            $response["result"] = "success";
            $response['message'] = count($records)." users found.";
            $response['items'] = $records;
    
        } else {
            // no records found
            $response['result'] = 'success';
            $response['message'] = 'No Users Found';
        }
    
        echoRespnse(200, $response);
    });
    
    /**
    *用户列表
    *url-/list
    *方法-获取
    */
    $app->get('/users/list',authenticate',function()使用($app){
    $response=array();
    $db=新的DbHandlerParse();
    $results=$db->getUserList();
    $records=array();
    //回显“已成功检索”。计数($results)。“分数。

    ”; //对返回的ParseObject值执行一些操作 对于($i=0;$igetObjectId(); $records[$i]['firstName']=$object->get('firstName'); $records[$i]['lastName']=$object->get('lastName'); $records[$i]['username']=$object->get('username'); $records[$i]['email']=$object->get('email'); //echo$object->getObjectId().'-'.$object->get('username')。
    '; } //检查返回的记录 如果有($记录){ $response[“result”]=“success”; $response['message']=计数($records)。“已找到用户。”; $response['items']=$records; }否则{ //没有发现任何记录 $response['result']='success'; $response['message']='No Users Found'; } EchoResponse(200美元响应); });
    为什么不使用默认的解析RESTAPI或云代码?(1) 我可能希望该应用程序与解析之外的其他几个服务集成。(2) 我可能需要几个遵循相同业务规则的界面(即移动应用程序和web应用程序)。使用公共API可以避免代码重复,并将复杂的模型逻辑从客户端应用程序中抽象出来。我只对PHP语法略知一二,但我认为您所做的和我所见过的任何方法一样好。事实上,从那以后我就不再使用解析了。我的逻辑在应用程序中变得太复杂了,所以我添加了一个相当简单的API层,其中包含Sails.js和一个Mongo数据库。谢谢你的投入和详尽的解释。