Обработка аутентификации для приложения 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 по ошибке: