【问题标题】:Handling authentication for PhoneGap app from CakePHP从 CakePHP 处理 PhoneGap 应用程序的身份验证
【发布时间】:2013-01-09 11:02:55
【问题描述】:

我正在构建一个内置在 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'));
}

如前所述,我可以通过将方法名称传递给$this-&gt;Auth-&gt;allow() 来保护beforeFilter 中的此方法。所以我假设我需要在 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 的帖子的 cmets。如果您未通过身份验证,您将获得以下内容:

{"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 登录表格。

【问题讨论】:

  • 如果我理解正确,您是在为 Forrst 本身构建应用程序?或者您是否使用 Forrst 作为您的用户管理系统?我确实有使用 Cordova (Phonegap) 和 CakePHP 的经验,所以我可能可以帮助你,但这个问题对我来说并不是 100% 清楚。您可以分享指向您正在使用的确切 API 的链接吗?因为我能找到关于这个 API 的唯一内容是 forrst.com/api,但它似乎是一个访问他们帖子的 API,而不是用户管理系统。所以我不明白您使用myserver.com 的第一个代码sn-p 和稍后使用的forrst.com 之间的链接。
  • 对不起,我只是使用 Forrst 作为我试图在 API 功能方面创建的示例。特别是返回的 JSON 的身份验证部分。 我没有使用 Forrst 的任何东西。
  • 好的,看看我的回答。我希望它能以某种方式帮助你:)

标签: jquery api cakephp cordova


【解决方案1】:

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

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

PostsController - index()

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

ajax layout 中,您可以告诉json_encode $data,然后它将被正确解析。

应用

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

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

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

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

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


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

【讨论】:

  • 这似乎很手动...我不能在 AppController 中添加一些东西来附加 JSON 请求以及状态、身份验证等附加数据吗?否则,我通过调用另一个控制器来调用另一个方法来打破约定。
  • @Cameron 你可以在你的控制器中进行检查,或者制作一个处理这些东西的组件。类似于 ApiComponent 的东西,其主函数名为 isApi(),因此您可以检查它是否是 Api 调用。 setApi 如果您想强制它成为 API 调用。有很多很多方法。但我建议在你的情况下使用一个组件,因为你有一个非常好的点不违反约定:) 但你最终会得到 if 语句。因为您需要安全的 JSON 输出而不是 html 输出。
  • 仍然不确定在登录表单以 HTML 形式返回之前我将如何跳转,而是将正确的错误数据作为 JSON 传递。有没有办法将它全局添加到 JSON 请求中?因为只检查 Ajax 调用并不是一个好习惯,因为我将 Ajax 用于其他事情,所以它会发生冲突。
  • 你可以设置默认的$this-&gt;Auth-&gt;allow(),这样它就会得到正确的方法。然后在方法本身中设置$this-&gt;Auth-&gt;deny()(如果需要),并调用parent::beforeFilter()。可能我有点破解,但我相信它的工作原理。我会建议使用新的 ApiController 。因为您正在处理不同类型的输出。所以只需用他们的方法调用正确的模型。胖模型,瘦控制器。我将与一些 CakePHP 人分享这个问题,也许他们可以帮助你,因为他们对 Cake 了如指掌:)
  • @Cameron 也许你想在 Skype 上加我什么。并就该主题进行一次头脑风暴会议?
【解决方案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;

在user表中,在用户注册的时候,简单的生成一些accesstoken并存储 它在列中说“访问令牌”。

用户登录时返回此令牌。

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

在您的 ajax 调用中使用帖子控制器中的 showPosts 方法 http://yourdomain.com/posts/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;}

【讨论】:

  • $method=$this->action; $Mmethods =array('test1,''test2'); //包含需要访问令牌的方法名称的数组 在控制器的 beforeFilter() 函数中,您可以这样做: if(in_array($method,$Mmethods)) { //检查访问令牌 //如果找不到令牌,返回错误响应并退出; }
  • 你能举一个更完整的例子吗?不太了解这将如何工作。谢谢。
  • Beforefilter() 方法在调用控制器中的所有其他方法之前被调用。所以如果用户访问令牌无效,我们将使用退出;用于停止将控制权传递给控制器​​中请求的方法的语句。另一方面,如果它是有效的,控制将传递给控制器​​中请求的方法。您是在 cakephp 或其他地方的某个控制器中执行 rqeuired 操作吗?
【解决方案3】:

为了澄清原因:您的用户是否需要“登录”才能在每种情况下查看返回的帖子,或者只有部分帖子需要用户登录?你有控制另一边的脚本(index.json)吗?

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

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

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

【讨论】:

  • index.json 只是一个例子。但基本上我需要知道一个方法是否需要身份验证,如果需要,然后将此信息传递回我的应用程序,以便我执行登录操作。它目前正在传回登录表单本身,这是我想要停止的。另一个问题是,如果我添加一些额外的 JSON 来说明用户是否登录,我只想在有意义的情况下关心受保护的方法。代码示例将不胜感激。
  • 关于返回的内容。如果该方法不受保护,那么它只会为帖子返回一个简单的 json 对象。如果它受到保护,那么我的 Cake 应用程序将返回实际的 HTML 登录视图 HTML。
  • 如果您查看我上面更新的帖子,您会发现我引用了 Forrst API。这就是我想要有效实现的目标。
【解决方案4】:

希望这样可以解决问题:

代码 sn-p 使用命名参数和is('ajax') 来确定一个json请求,并检查用户是否尚未登录。然后如果请求的操作需要身份验证,它只会发送一个json错误:

首先,把这个放在你的beforeFilter()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-&gt;Auth-&gt;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
    //...
}

【讨论】:

    【解决方案5】:

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

    【讨论】:

    • 我的应用程序如何知道何时请求身份验证?因为它目前只是将 HTML 表单返回给 PhoneGap 应用程序。
    • 你是说如果你的ajax调用没有传递auth参数,并且需要认证,你会被退回到原始的html登录页面,而没有任何需要认证的迹象?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 1970-01-01
    • 2013-03-13
    • 1970-01-01
    相关资源
    最近更新 更多