#cakephp #basic-authentication
#cakephp #базовая аутентификация
Вопрос:
Я пытаюсь настроить базовую аутентификацию для своего приложения CakePHP, чтобы я мог использовать его в качестве API для будущего мобильного приложения. Однако, если я передам следующее:
cameron:password@dev.driz.co.uk/basic/locked/
Где cameron — это имя пользователя, password — это пароль, а остальное — домен и приложение. locked
это метод, который требует аутентификации. (очевидно, что в этом примере пароль неверен)
(Q1) В приглашении мне будет предложено ввести имя пользователя и пароль… но имя пользователя и пароль на самом деле правильные, как если бы я затем ввел их в приглашение, они работают… Почему это должно произойти?Разве я только что не передал имя пользователя и пароль?
Я не вижу ничего плохого в том, как я настроил это в CakePHP.
Я установил базовую аутентификацию в AppController как:
public $components = array('Auth');
function beforeFilter()
{
parent::beforeFilter();
$this->Auth->authorize = array('Controller');
$this->Auth->authenticate = array('Basic');
$this->Auth->sessionKey = false;
$this->Auth->unauthorizedRedirect = false;
}
(Q2) Несмотря на это, я установил для обоих сеансов значение false, а для перенаправления значение false, если пользователь отменяет запрос, они перенаправляются на страницу входа в систему? Есть идеи о том, как остановить это? В идеале я хочу отправить ответ JSON или код состояния 401 (в зависимости от того, является ли это AJAX-запросом или нет).
Итак, что-то вроде:
if ($this->request->is('ajax')) {
$response = json_encode(
array(
'meta'=>array(
'code'=>$this->response->statusCode(401),
'in'=>round(microtime(true) - TIME_START, 4)
),
'response'=>array(
'status'=>'error',
'message'=>'401 Not Authorized'
)
)
);
// Handle JSONP
if(isset($_GET['callback'])) {
$response = $_GET['callback'] . '(' . $response . ')';
}
// Return JSON
$this->autoRender = false;
$this->response->type('json');
$this->response->body($response);
} else {
header('HTTP/1.0 401 Unauthorized');
}
Но куда это приведет в логике приложения, чтобы показать это? Это должно произойти для ВСЕХ запрошенных методов, требующих аутентификации, и пользователь завершает или отменяет аутентификацию.
(Q3) Если вы вводите неправильные данные, вам просто снова отображается приглашение, пока вы не получите правильное имя пользователя / пароль или не нажмете «Отмена». Как я могу заставить его показывать ошибку?
Любые идеи по этим трем вопросам (помечены как номера дополнительных вопросов).
Обновление: вот как я отправляю заголовки в API:
"use strict";jQuery.base64=(function($){var _PADCHAR="=",_ALPHA="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /",_VERSION="1.0";function _getbyte64(s,i){var idx=_ALPHA.indexOf(s.charAt(i));if(idx===-1){throw"Cannot decode base64"}return idx}function _decode(s){var pads=0,i,b10,imax=s.length,x=[];s=String(s);if(imax===0){return s}if(imax%4!==0){throw"Cannot decode base64"}if(s.charAt(imax-1)===_PADCHAR){pads=1;if(s.charAt(imax-2)===_PADCHAR){pads=2}imax-=4}for(i=0;i<imax;i =4){b10=(_getbyte64(s,i)<<18)|(_getbyte64(s,i 1)<<12)|(_getbyte64(s,i 2)<<6)|_getbyte64(s,i 3);x.push(String.fromCharCode(b10>>16,(b10>>8)amp;255,b10amp;255))}switch(pads){case 1:b10=(_getbyte64(s,i)<<18)|(_getbyte64(s,i 1)<<12)|(_getbyte64(s,i 2)<<6);x.push(String.fromCharCode(b10>>16,(b10>>8)amp;255));break;case 2:b10=(_getbyte64(s,i)<<18)|(_getbyte64(s,i 1)<<12);x.push(String.fromCharCode(b10>>16));break}return x.join("")}function _getbyte(s,i){var x=s.charCodeAt(i);if(x>255){throw"INVALID_CHARACTER_ERR: DOM Exception 5"}return x}function _encode(s){if(arguments.length!==1){throw"SyntaxError: exactly one argument required"}s=String(s);var i,b10,x=[],imax=s.length-s.length%3;if(s.length===0){return s}for(i=0;i<imax;i =3){b10=(_getbyte(s,i)<<16)|(_getbyte(s,i 1)<<8)|_getbyte(s,i 2);x.push(_ALPHA.charAt(b10>>18));x.push(_ALPHA.charAt((b10>>12)amp;63));x.push(_ALPHA.charAt((b10>>6)amp;63));x.push(_ALPHA.charAt(b10amp;63))}switch(s.length-imax){case 1:b10=_getbyte(s,i)<<16;x.push(_ALPHA.charAt(b10>>18) _ALPHA.charAt((b10>>12)amp;63) _PADCHAR _PADCHAR);break;case 2:b10=(_getbyte(s,i)<<16)|(_getbyte(s,i 1)<<8);x.push(_ALPHA.charAt(b10>>18) _ALPHA.charAt((b10>>12)amp;63) _ALPHA.charAt((b10>>6)amp;63) _PADCHAR);break}return x.join("")}return{decode:_decode,encode:_encode,VERSION:_VERSION}}(jQuery));
$(document).ready(function(){
var username = 'cameron';
var password = 'password';
$.ajax({
type: 'GET',
url: 'http://dev.driz.co.uk/basic/locked',
beforeSend : function(xhr) {
var base64 = $.base64.encode(username ':' password);
xhr.setRequestHeader("Authorization", "Basic " base64);
},
dataType: 'jsonp',
success: function(data) {
console.log(data);
},
error: function(a,b,c) {
//console.log(a,b,c);
}
});
});
Ответ №1:
Вопрос 1
Вы не указываете, как вы посещаете защищенный URL-адрес (dev.driz.co.uk/basic/locked ). Вы уверены, что то, как вы это делаете, правильно настраивает заголовки запросов? Вам нужно кодировать имя пользователя / пароль в Base64.
Когда ваш первый запрос завершается неудачно, браузер выдает запрос, и успех означает, что браузер выполняет его правильно для вас во второй раз.
Посмотрите на заголовки ваших запросов, чтобы увидеть, что вы отправляете в первый раз, а что браузер отправляет во второй.
Вопрос 2
При сбое базовой аутентификации ваш сервер отправляет a 401
с заголовком WWW-Authenticate:Basic
, который извлекается из браузера, и вам выдается приглашение. Это обычное поведение для всех браузеров с незапамятных времен, вы не можете это изменить.
Что касается вашей проблемы с отменой и перенаправлением на вход в систему, у Auth были некоторые изменения API после 2.4, которые выделены в книге. До версии 2.4 вы всегда перенаправлялись на loginAction.
Наконец, позвольте Auth
выполнить всю работу за вас, правильно настроив ее, и не пытайтесь самостоятельно настраивать ответы, как в предлагаемом вами коде. Вы также никогда не должны использовать php header()
в cakephp, используйте CakeRequest::header()
вместо этого.
Вопрос 3
Отвечая на вопрос Q2, вы не можете заставить Basic и 401 не запускать запрос. Либо измените требуемый заголовок аутентификации (возможно, установив имя типа Basic-x вместо Basic), либо не отправляйте код ответа 401 при сбое, а отправьте, например, 200 или 400 и добавьте сообщение об ошибке, объясняющее ситуацию.
Комментарии:
1. Для Q3, когда вы говорите
or don't send the response code 401 on failure but send i.e. 200 or 400 and add an error message explaining the situation.
, как вы это делаете? Похоже, вы подразумеваете, что можете сделать это без изменения заголовка… Не могли бы вы показать пример?2. Вы можете создать свое собственное пользовательское исключение и указать код состояния в качестве второго параметра или создать встроенное исключение
3. Я обновил свой код CakePHP до 2.5.2, но когда я выполняю приведенный выше JS-код, я вижу приглашение для входа в систему из браузера… таким образом, как будто он запрашивает аутентификацию, чтобы иметь возможность фактически отправить запрос через AJAX, если это имеет смысл? Несмотря на то, что заголовки задаются в опции beforeSend! Можете ли вы увидеть какую-либо причину, почему? Имя пользователя и пароль указаны правильно, как будто я ввожу их в приглашение, и тогда это работает! Но даже если они были неверными, я не хочу видеть приглашение и вместо этого показываю ошибку только в моем JS…
4. Я не знаю, верна ли ваша функция base64, я бы использовал внутреннюю функцию
btoa()
для ее кодирования, которая работает. И если вы не хотите, чтобы приглашение читало то, что я объясняю в Q3, где я говорю о заголовках, отправляемых с сервера.5. Пробовал, но заголовки никогда не отправляются (просматриваются в веб-инспекторе), потому что у него нет доступа для их отправки, поскольку он еще не авторизован… и если я введу свои данные в приглашение, а затем обновлю страницу с включенным JS, тогда заголовки будут отправлены JS … почему это происходит? Я думал, что beforeSend обработал это, чтобы отправить заголовки ПЕРЕД запросом?