Обработка аутентификации для приложения PhoneGap от CakePHP

Я создаю простое приложение, встроенное в PhoneGap, которое использует REST API для загрузки данных с моего сайта на сервере (потому что вы не можете запускать PHP внутри 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 вместо того, чтобы возвращать форму входа в систему из приложения, как она сейчас делает? Возможно, отправив запрос авторизации через JSON?

В качестве примера простой метод JSONized выглядит так:

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

И как было сказано ранее, я могу защитить этот метод в beforeFilter не, передав имя метода в $this->Auth->allow(). Поэтому я предполагаю, что мне нужно будет сделать что-то умное в файле beforeFilter, чтобы узнать, является ли этот запрос JSON, и если да, то проверьте, требует ли метод авторизации, а затем, если это так, отправьте ошибку (вместо HTML-формы как Cake обычно через AuthComponent) в JSON или разрешить доступ.

ОБНОВЛЕНИЕ: 13 января 2012

После нескольких исследований по этому вопросу я рассмотрел API Forrst, поскольку они, похоже, эффективно создали то, что я собираюсь построить с точки зрения API RESTful.

Например, у них есть вызов типа: https://forrst.com/api/v2/post/comments?tiny_id=HUD, это в основном говорит о том, чтобы отображать комментарии для сообщения с крошечным идентификатором HUD. То, что вы получите, следующее: если вы не прошли аутентификацию:

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

Теперь интересная часть EVEN, если я зашел в Forrst, я все равно получаю это сообщение об ошибке, потому что он не смотрит на мою сессию, а ожидает, что какой-то токен аутентифицирует фактический запрос. например ?access_token=550e8400-e29b-41d4-a716-446655440000

Итак, главный вопрос, который я предполагаю, заключается в том, как я могу создать это в своем приложении Cake? План выглядит следующим образом:

В моем приложении он перенаправил бы вас на страницу входа, независимо от того, запросили ли вы ее через AJAX или в браузере. Forrst обрабатывает оба и ALWAYS возвращает ошибки JSON при вызове API и не возвращает HTML никогда! Это то, чего я хочу достичь в своей реализации. Я добавил столбец access_token в таблицу моих пользователей (которая изменяется всякий раз, когда кто-либо обновляет свой пароль по соображениям безопасности). Следующим шагом будет A) проверить этот токен доступа для защищенных методов и разрешить или запретить, если он будет исправлен, а затем B) Мне нужно каким-то образом обрабатывать, когда не существует или неверен токен, и отправляет правильный статус ошибки вместо входа в HTML форма.

Ответ 1

У нас была та же проблема с нашим приложением, также встроенная в Phonegap (теперь она называется Cordova). Это была настоящая боль, чтобы заставить аутентификацию работать, но в итоге нам удалось заставить ее работать с использованием API Facebook, но я предполагаю, что вы не хотите использовать 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->Auth->allow(), он даже не войдет туда, если вы не вошли в систему. Так что вам нужно сделать новый AjaxController, который обрабатывает первый запрос. Просто разместите код, указанный выше в beforeFilter, и сделайте свою магию оттуда. Оттуда вы можете просто проверить, зарегистрирован ли кто-то и что такое текущее состояние пользователя. Если он вошел в систему и вы хотите вернуть данные. Вы можете вызвать требуемую модель или вызвать функцию контроллера с помощью requestAction('/path/to/what/i/need'), где необходимый вам путь может быть объявлен в переменной post, которую вы отправили в вызове Ajax.

В ajax layout вы можете указать json_encode $data, который будет корректно проанализирован.

приложения

Теперь в вашем JavaScript вы получите некоторые данные. Скажем, вы структурируете возвращаемую строку JSON со следующими ключами: status и data.

Скажем, status был установлен в auth в возвращенном JSON, вы знаете, что вам нужно пройти аутентификацию, чтобы вы могли показать форму входа, которая затем обрабатывает все эти вещи. Просто сделайте приятный вид входа в приложение, чтобы вы могли контролировать все его аспекты и, надеюсь, сделать его более безопасным.

Если status установлено в success, вы можете затем показать все сообщения соответственно.

У меня есть ответ на другую тему, где я покажу, как мы создали наш собственный API, возможно, это может помочь вам каким-то образом: fooobar.com/questions/538911/...

предупреждение JavaScript, похоже, безопасен в приложении Phonegap, но это не так! Любой пользователь может загрузить с него Android файл .apk и открыть его в Android emulator, который затем сможет просмотреть все JavaScript и HTML-код. Поэтому будьте очень осторожны с данными, которые вы собираетесь кодировать непосредственно в JavaScript и как ваш API доступен.


Я знаю, что мой ответ нечеткий, поэтому, если вам нужна дополнительная информация об этом ответе, пожалуйста, спросите!

Ответ 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".

Этот токен возвращается, когда пользователь входит в систему.

Таким образом, вы можете добавить его к вашему аякс-коду при отправке запроса.

Скажите метод showPosts в контроллере сообщений в вашем вызове 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;}

Ответ 3

По соображениям разъяснения: должны ли ваши пользователи "войти в систему", чтобы просмотреть возвращаемые сообщения в каждом случае, или только некоторые сообщения требуют, чтобы пользователи вошли в систему? У вас есть контроль над script с другой стороны (index.json)?

Из моего понимания прямо сейчас я бы использовал страницу в приложении PhoneGap для "входа в систему", затем сохранил и отправил информацию вместе с запросом на сервер index.json или лучше PHP скрипт, который может обрабатывать и верните соответствующую строку json. В основном, как сеансовые куки работают в типичном браузере.

Другой вариант - вы можете изменить index.json, чтобы вернуть строку json, содержащую сообщение, которое вы могли бы поймать, прочитать и обработать в PhoneGap, а затем, если необходимо, показать пользователю форму входа в ваше приложение, как указано выше.

Я хочу помочь с кодом и примерами, однако ваш текущий пост нечетко описывает ваш текущий код и то, что возвращается с сервера.

Ответ 4

Надеюсь, это будет трюк:

Фрагмент кода использует именованный параметр вместе с 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() перед вызовом parent::beforeFilter() обязательно добавьте разрешенные действия $this->Auth->allow.

Если вы используете более расширенную аутентификацию с помощью списков контроля доступа (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/), используйте их и обрабатывайте ошибки auth по ошибке: