2013-01-09 91 views
10

我正在構建一個使用REST API從服務器上的我的網站加載數據的PhoneGap中構建的簡單應用程序(因爲您無法在PhoneGap中運行PHP)。從CakePHP處理對PhoneGap應用程序的身份驗證

上市的一些數據可能是一個例子:

$.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發送一個auth請求?

舉個例子簡單JSONized方法是這樣的:

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

而且如前所述我可以傳遞方法的名稱爲$this->Auth->allow()保護在beforeFilter此方法。所以我假設我需要在beforeFilter中做一些聰明的事情來知道請求是否是JSON,如果是,那麼檢查該方法是否需要授權,然後如果是這樣,或者發回錯誤(而不是HTML格式,如Cake通過AuthComponent)在JSON中或允許訪問。

更新: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登錄形成。

+0

如果我正確理解你,你正在爲Forrst本身構建一個應用程序?或者您是否將Forrst用作您的用戶管理系統?我有Cordova(Phonegap)和CakePHP的經驗,所以我可以幫助你,但這個問題並不是100%清楚。你能分享一個鏈接到你正在使用的確切的API嗎?因爲我能找到關於這個API的唯一信息是https://forrst.com/api,但它似乎是一個訪問他們的帖子的API,而不是一個用戶管理系統。所以我不明白你的第一個使用'myserver.com'的代碼段和'forrst.com'之間的關係。 – Jelmer

+0

對不起,我只是用Forrst作爲我試圖創建的API功能的一個例子。特別是JSON的驗證部分返回。 **我沒有使用任何來自Forrst。** – Cameron

+0

好的,看看我的答案。我希望它能以某種方式幫助你:) – Jelmer

回答

1

jQuery ajax()函數使您能夠通過使用用戶名和密碼(http://api.jquery.com/jQuery.ajax/)將請求和請求一起傳遞,使用這些和處理驗證失敗的錯誤:

+0

我的應用程序如何知道何時請求身份驗證?因爲它目前只是將HTML表單返回給PhoneGap應用程序。 – Cameron

+0

您是否在說如果您的ajax調用未通過身份驗證參數,並且需要身份驗證,那麼您會在沒有任何指示需要身份驗證的情況下反彈到原始html登錄頁面? – ElasticThoughts

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; 

在用戶表中,在用戶註冊時,簡單地生成一些accesstoken並將其存儲在一列中稱爲'accesstoken'。

此令牌返回時。

用戶登錄所以,您可以在發送請求添加到您的AJAX調用。

說showPosts方法posts控制器在你的Ajax調用 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;} 
+0

$ method = $ this-> action; $ Mmethods = array('test1,''test2'); //數組中包含需要訪問令牌的方法的名稱在控制器的beforeFilter()函數中,可以這樣做:if(in_array($ method,$ Mmethods)){//檢查訪問令牌//如果未找到令牌,返回錯誤並退出; } – cartina

+0

你能展示一個更完整的例子嗎?不太瞭解這將如何工作。謝謝。 – Cameron

+0

Beforefilter()方法在調用控制器中的每個其他方法之前被調用。所以如果用戶訪問令牌無效,我們將使用exit;語句停止將控制權傳遞給控制器​​中的請求方法。另一方面,如果它是有效的,控制將傳遞給控制器​​中的請求方法。你是否在cakephp或其他地方的某個控制器中執行了需要執行的操作? – cartina

2

爲了區別起見:你的用戶需要「登錄」,以在任何情況下查看返回崗位,或只有一些帖子要求用戶登錄?你對另一邊的劇本有控制嗎?(index.json)

從我現在的理解我會使用PhoneGap應用程序中的一個頁面來「登錄」,然後存儲和發送信息以及請求到服務器index.json或更好的PHP腳本,可以處理並返回適當的json字符串。基本上,Session Cookies如何在典型的瀏覽器中工作。

另一種選擇是,你可以修改index.json返回包含一個信息,即你​​能趕上,閱讀和處理在PhoneGap的一個json字符串,然後在需要時顯示應用中的用戶登錄表單,然後做一樣的以上段落。

我願意幫助您的代碼和示例,但是您當前的帖子對您​​當前的代碼和服務器返回的內容很模糊。

+0

index.json只是一個例子。但基本上我需要知道一個方法是否需要身份驗證,如果是,請將這些信息傳回給我的應用程序,以便我執行登錄。目前它正在傳遞登錄表單本身,這是我想要停止的。另一個問題是,如果我添加一些額外的JSON來說用戶是否登錄,我只想關心這個保護方法,如果這是有道理的。代碼示例將非常感謝。 – Cameron

+0

關於返回的內容。如果該方法沒有被保護,那麼它只是爲帖子返回一個簡單的json對象。如果它受到保護,那麼我的Cake應用程序將返回實際的HTML登錄視圖HTML。 – Cameron

+0

如果你看看我上面更新的帖子,你可以看到我引用了Forrst API。這正是我想要有效實現的目標。 – Cameron

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調用發送的後期變量中聲明。

ajax layout,你可以告訴json_encode$data然後將被正確解析。

應用

現在在你的JavaScript,你會得到一些數據。假設您使用以下鍵構造返回的JSON字符串:statusdata

假設status已經在返回的JSON中設置爲auth,您知道您需要進行身份驗證,因此您可以顯示一個登錄表單,然後處理所有這些信息。只需在應用程序中創建一個漂亮的登錄視圖,以便您可以控制它的每個方面,並希望更安全。

如果status設置爲success,則可以相應地顯示所有帖子。

我有一個答案到另一個話題,我展示瞭如何創建我們自己的API,也許可以幫助你以某種方式:https://stackoverflow.com/a/11422866/1110760

警告的JavaScript似乎是安全的PhoneGap的應用程序,但它不是!任何人都可以從它的Android設備下載.apk文件,然後在Android emulator中打開它,然後他可以查看所有JavaScript和HTML代碼。因此,要謹慎處理要直接寫入JavaScript的數據以及您的API的訪問方式。


我知道我的答案是有點模糊,所以如果您需要更多關於這個答案的更多信息,請諮詢!

+0

這似乎是非常手動的...我可以不添加的東西在AppController附加JSON請求與附加數據,如狀態,身份驗證等?否則,我通過調用另一個控制器在另一個控制器中調用某個方法來打破慣例。 – Cameron

+0

@Cameron你可以在你的控制器中進行檢查,或者製作一個處理這些東西的組件。就像一個叫做'isApi()'的主函數的ApiComponent,所以你可以檢查它是否是一個Api調用。而'setApi'如果你想強制它成爲一個API調用。有許多方法。但我會建議在你的情況下使用一個組件,因爲你有一個非常好的觀點,不會違反約定:)但是最終你會以if語句結束。因爲你需要安全的JSON輸出而不是html輸出。 – Jelmer

+0

仍然不確定如何在登錄表單返回爲HTML之前跳入,並將正確的錯誤數據作爲JSON傳遞。有沒有辦法將這個全局添加到JSON請求?檢查Ajax調用並不是好的做法,因爲我使用Ajax來處理其他事情,所以它會發生衝突。 – Cameron

2

希望這將這樣的伎倆:

的代碼片段一起使用命名參數與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->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 
    //... 
} 
相關問題