Определите, какая часть (части) инструкции WHERE Завершилась с ошибкой
-
05-07-2019 - |
Вопрос
Допустим, у меня есть оператор SQL, подобный этому, который проверяет логин пользователя:
SELECT * FROM users
WHERE username='test@example.com', password='abc123', expire_date>=NOW();
Есть ли в SQL способ конкретно определить, какие условия WHERE не выполняются, без необходимости разделять каждое условие на его собственный запрос и тестировать по отдельности?
В этом конкретном примере это позволило бы разработчику точно указать пользователям причину, по которой их попытка входа в систему завершилась неудачей.
Для своих целей я использую PHP / MySQL.
Решение 5
Вот что я придумал:
SELECT
IF(mem_username='test@example.com','true','Error: Bad Username') AS mem_username,
IF(mem_password ='abc123','true','Error: Bad Password') AS mem_password'
FROM MEMBERS
WHERE mem_username='test@example.com' AND mem_password='abc123'
Таким образом, я могу обнаружить в коде сообщения об ошибках, а затем отобразить их при необходимости.
ПРИМЕЧАНИЕ. Всем, кто ссылается на соображения безопасности в примере кода, спасибо за внимание. Тем не менее, это не настоящий производственный код, это был простой пример, демонстрирующий мой вопрос. Совершенно очевидно, что вы не должны хранить пароли в виде открытого текста, и что вы не должны давать пользователям конкретные сведения о том, почему не удается войти в систему.
Другие советы
Ну, одну вещь, которую вы могли бы сделать, это изменить запрос так, чтобы он совпадал только с именем пользователя. Затем в коде вы проверяете пароль и срок действия, возвращая соответствующие ошибки.
Кроме того, я надеюсь, что ваш пример запроса является упрощением; Конечно, вы должны защищать / шифровать / хэшировать свои пароли, и вы должны включить что-то, что ограничивает количество неудачных попыток в течение определенного периода времени и т. Д.
Что касается вашего фактического вопроса (в отличие от результатов, которые вы ищете), нет способа получить эту информацию из предложения where. Самое близкое, что вы можете сделать, это что-то вроде:
SELECT *,
CASE WHEN Password = 'asdf' THEN 1 ELSE 0 END AS IsPasswordMatch,
CASE WHEN Expiration >= NOW() THEN 1 ELSE 0 END AS IsActiveAccount
FROM Users
WHERE Username = 'user'
В MySQL вы можете помещать логические выражения в список выбора. Булевы выражения оцениваются в целое число 1, если оно истинно, или в целое число 0, когда ложно.
SELECT password = 'abc123' AS is_authenticated,
expire_date >= NOW() AS is_not_expired
FROM users
WHERE username='test@example.com';
note: Если вам нужно написать запрос, который работает с другими брендами СУБД, имейте в виду, что использование логических выражений не является стандартным. Используйте синтаксис CASE
, опубликованный другими людьми.
PS: Это касается вашего вопроса, но я призываю вас не хранить пароли в открытом виде. Сохраните хэш-дайджест соленого пароля. См. Как соль пароля помогает против атаки с помощью радужного стола?
Нет, предложение where- применяется как блок, и используются различные методы, чтобы не нужно было сканировать все строки.Кроме того, как бы вы узнали, какая строка была нужной?
Кроме того, вы, вероятно, не хотите слишком много рассказывать пользователю о том, почему попытка входа в систему завершилась неудачей.Слишком много говорящий человек допускает такие эксплойты, как минирование учетных записей и атаки паролями.
Редактировать Если вы действительно хотите отобразить это своему пользователю, то разделите свою логику на разные части:
- Проверка подлинности
Экшен:Извлеките соответствующую строку пользователя из базы данных
Результат:- Если такой строки не существует => недопустимая учетная запись
- Если строка возвращена, перейдите к шагу 2.
- Проверка учетных данных
Экшен:Сверьте сохраненные учетные данные (пароль, хэш пароля или зашифрованный пароль) с предоставленным паролем, обработанным таким же образом, как хранятся учетные данные.
Результат:- Нет совпадения => Неверный пароль / учетные данные
- Совпадение => Успешная попытка входа в систему
- Войти в систему пользователя
Экшен:Добавление данных в сеанс и т.д.
Вероятно, вам просто нужно разделить части предложения where с помощью AND.
SELECT * FROM users
WHERE username='test@example.com'
And password='abc123'
And expire_date>=NOW();