10

我正在构建一个内置在 PhoneGap 中的简单应用程序,它使用 REST API 从服务器上的我的网站加载数据(因为您不能在 PhoneGap 中运行 PHP)。

列出一些数据的示例可能是:

$.ajax({
    url: 'http://myserver.com/posts/index.json',
    dataType: 'jsonp',
    success: function(data) {
        for (var i=0,total=data.length; i<total; i++)
        { 
            console.log(data.Post.title[i]);
        }
    }
});

这很好,返回的数据可以在我的 PhoneGap 应用程序中使用。但是,假设帖子列表要求您登录...

我将如何处理?因为与重定向到登录表单的正常身份验证请求不同,在我的 JSON 世界中,这不会发生。事实上,实际的 HTML 登录表单被返回,这会导致错误,因为我的 JavaScript 需要 JSON 而不是 HTML。

是否有处理此问题的最佳实践,例如如果请求身份验证然后在 PhoneGap 应用程序中加载登录表单视图,而不是像当前那样从应用程序返回 HTML 登录表单?也许通过 JSON 发送身份验证请求?

例如,一个简单的 JSON 化方法如下所示:

public function index() {
    $this->set('posts', $this->paginate());
    $this->set('_serialize', array('posts'));
}

如前所述,我可以beforeFilter通过将方法名称传递到$this->Auth->allow(). 所以我假设我需要在 beforeFilter 中做一些聪明的事情来知道请求是否是 JSON,如果是,那么检查该方法是否需要授权,然后如果需要,要么发回错误(而不是像 Cake 通常的 HTML 表单在 JSON 中通过 AuthComponent) 或允许访问。

更新:2012 年 1 月 13 日

在对该主题进行了更多研究之后,我查看了 Forrst API,因为它们似乎已经有效地构建了我想要构建的 RESTful API。

例如,他们有这样的电话:https ://forrst.com/api/v2/post/comments?tiny_id= HUD 这基本上是说显示带有 HUD 小 id 的帖子的评论。如果您未通过身份验证,您将获得以下内容:

{"resp":{"error":"this method requires authentication"},"stat":"fail","in":0.0903,"authed":false,"authed_as":false,"env":"prod"}

现在有趣的部分是即使我登录到 Forrst,我仍然会收到该错误消息,因为它没有查看我的会话,而是期待某种令牌来验证实际请求。例如?access_token=550e8400-e29b-41d4-a716-446655440000

所以我想这里的主要问题是如何将它构建到我的 Cake App 中?计划如下:

在我的应用程序中,无论您是通过 AJAX 还是在浏览器中请求它,它都会将您重定向到登录页面。Forrst 处理两者,并且在调用它的 API 时总是返回 JSON 错误,并且永远不会返回 HTML!这就是我想要在我的实现中实现的目标。我在我的用户表中添加了一个 access_token 列(出于安全原因,每当有人更新密码时,该列都会更改)。下一步是 A) 检查受保护方法的访问令牌,如果正确则允许或拒绝,然后 B) 当不存在令牌或不正确时,我需要某种方式进行处理,并发送正确的错误状态而不是 HTML 登录形式。

4

5 回答 5

4

我们的应用程序也存在同样的问题,该应用程序也内置在 Phonegap(现在称为 Cordova)中。让身份验证工作真的很痛苦,但最终我们设法通过使用 Facebook API 让它工作,但我假设你不想使用 Facebook。

因此,您可以通过运行以下代码来检查它是否是 XMLHttpRequest:

PostsController - 索引()

if ($this->RequestHandler->isAjax() == 1){
    // This is an Ajax call
    $this->layout = 'json';
    $this->set('data', array('data', 'to', 'parse'));
} else {
    // This is the normal request
    # do the stuff you want to do here as usual
}

但是由于这会要求您登录,因为它不在$this->Auth->allow()列表中,除非您登录,否则它甚至不会到达那里。所以您需要做的是创建一个新的AjaxController来处理第一个请求。只需将上面发布的代码放在上面,beforeFilter然后从那里做你的魔法。从那里您可以简单地检查是否有人登录以及用户的当前状态。如果他已登录并且您要返回数据。您可以调用您需要的模型或调用控制器函数,requestAction('/path/to/what/i/need')其中您需要的路径可以在您在 Ajax 调用中发送的 post 变量中声明。

在 中,ajax layout您可以告诉whichjson_encode$data被正确解析。

应用程序

现在在您的 JavaScript 中,您将获得一些数据。假设您使用以下键构造返回的 JSON 字符串:statusdata.

假设statusauth在返回的 JSON 中设置为,您知道您需要进行身份验证,因此您可以显示一个登录表单,然后处理所有这些内容。只需在应用程序中制作一个漂亮的登录视图,这样您就可以控制它的各个方面,并希望它更安全。

如果status设置为success您可以相应地显示所有帖子。

我有另一个主题的答案,我展示了我们如何创建自己的 API,也许这可以在某种程度上帮助你:https ://stackoverflow.com/a/11422866/1110760

警告JavaScript 在 Phonegap 应用程序中似乎是安全的,但事实并非如此!任何人都可以从其 Android 设备上下载 .apk 文件并在Android emulator能够查看所有 JavaScript 和 HTML 代码的人中打开它。因此,要非常小心您将直接编码到 JavaScript 中的数据以及您的 API 是如何访问的。


我知道我的答案有点含糊,所以如果您需要有关此答案的更多信息,请询问!

于 2013-01-14T16:28:53.217 回答
2

据我所知,如果用户未登录,您需要某种方式来返回一些错误消息,例如需要以 json 格式登录。您可以做的是构建如下函数:

    public function index ($token=NULL)
{
  if($token != NULL)
  {
   // call some method to check if token is valid
   // do required processing 
  }
  else
{
  $response=array('response'=>'failure','message'=>'Login required');
  echo json_encode($response);
}  

在ajax调用中:

 url: 'http://myserver.com/posts/index.json/'+token;

在用户表中,在用户注册时,简单地生成一些访问令牌并将其存储在“访问令牌”列中。

用户登录时返回此令牌。

因此,您可以在发送请求时将其添加到您的 ajax 调用中。

然后 在您的 ajax 调用http://yourdomain.com/posts/showPosts中的帖子控制器中说 showPosts 方法

$method=$this->action; //this fetches the name of the method called                                                   
$Mmethods =array('showPosts','test2'); // methods requiring login                                                               
if(in_array($method,$Mmethods)) {                                  
$this->params array will give you all the parameters passed in URL.
//Fetch the access token from this array if it is set in 'url' index //of this array.                          
//if token is found, run sql query whether it exists in database or //not, else return response with errors and exit;}
于 2013-01-11T11:46:42.973 回答
2

出于澄清原因:您的用户是否需要“登录”才能在每种情况下查看返回的帖子,或者只有一些帖子需要用户登录?您是否可以控制另一端的脚本(index.json)

根据我现在的理解,我会使用 PhoneGap 应用程序中的一个页面来“登录”,然后将信息与请求一起存储并发送到服务器index.json,或者更好的是可以处理和返回适当json字符串的 php 脚本。基本上会话 Cookie 在典型浏览器中的工作方式。

另一种选择是您可以修改index.json返回一个json字符串,其中包含您可以在 PhoneGap 中捕获、阅读和处理的消息,然后如果需要在您的应用程序中向用户显示登录表单,然后执行与上述段落相同的操作。

我愿意为代码和示例提供帮助,但是您当前的帖子对您​​当前的代码以及从服务器返回的内容含糊不清。

于 2013-01-12T22:33:23.343 回答
2

希望这可以解决问题:

代码片段使用命名参数 withis('ajax')来确定 json 请求,并检查用户是否尚未登录。然后,如果请求的操作需要身份验证,则仅发送 json 错误:

首先,把它放在你的beforeFilter()in 中AppController

//see if request is json (json is sent by adding a named param e.g. posts/index/json:1
//if so also check that user not already logged in
if (!empty($this->params['named']['json']) && $this->request->is('ajax') &&  !$this->Auth->user())
{
    //see if the action needs authentication
    $requiresAuth = !in_array($this->params['action'], $this->Auth->allowedActions);
    if ($requiresAuth)
    {
        //send json response
        $response = array('error' => 
            array(
                'code' => 123,
                'message' => 'authError',
            )
        );
        echo json_encode($response);
        exit;
    }
}

要发出请求 json,请添加/json:1到您的路径(例如http://myserver.com/posts/index/json:1,作为命名的 $_GET 参数)。在每个控制器beforeFilter()中,确保在调用$this->Auth->allow 之前parent::beforeFilter()首先添加允许的操作。

如果您使用访问控制列表 (ACL) 进行更高级的身份验证,请参阅http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html,您还需要了解如果 ACL 中允许该操作:

//the group_id to check permission for (must exist)
$group_id = 8; //your group_id
$group = array(
    'model' => 'Group',
    'foreign_key' => $group_id
);
$actionPath = $this->name . '/' . $this->params['action'];
$requiresAclAuth = $this->Acl->check($group, $actionPath);

查看 ACL 是否需要身份验证:

if ($requiresAclAuth && $requiresAuth)
{
    //send json response
    //...
}
于 2013-01-16T16:41:42.033 回答
1

jQuery ajax() 函数使您能够使用用户名:和密码:(http://api.jquery.com/jQuery.ajax/) 将登录信息与请求一起传递,使用这些并处理身份验证失败错误:

于 2013-01-11T11:35:43.213 回答