Ручной вход пользователя без пароля
-
03-10-2019 - |
Вопрос
Надеюсь, вы поможете мне найти лучший способ реализовать вход в систему вручную (инициируемый на стороне сервера). без используя пароль.Поясню рабочий процесс:
- Регистры пользователей
- Спасибо!Было отправлено письмо со ссылкой для активации blablabla
- (Аккаунт теперь существует, но помечен как неактивный)
- Пользователь открывает электронное письмо, нажимает ссылку
- (Аккаунт активирован)
- Спасибо!Теперь вы можете использовать сайт
Я пытаюсь войти в систему пользователя после того, как он щелкнул ссылку электронной почты, чтобы он мог сразу начать использовать веб-сайт.
Я не могу использовать его пароль, поскольку он зашифрован в базе данных. Является ли единственный вариант написать собственный сервер аутентификации?
Решение
Для входа в систему вам не нужен пароль.А auth.login
функция просто занимает User
объект, который вы, предположительно, уже получаете из базы данных при включении учетной записи.Таким образом, вы можете передать это прямо login
.
Конечно, вам нужно будет быть очень будьте осторожны, чтобы пользователь не мог подделать ссылку на существующую уже включенную учетную запись, которая затем автоматически войдет в систему как этот пользователь.
from django.contrib.auth import login
def activate_account(request, hash):
account = get_account_from_hash(hash)
if not account.is_active:
account.activate()
account.save()
user = account.user
login(request, user)
...и т. д.
Отредактировано:
Хм, не заметил требования использовать authenticate
из-за дополнительного свойства, которое оно добавляет.Глядя на код, все, что он делает, это backend
атрибут, эквивалентный пути к модулю серверной части аутентификации.Итак, вы можете просто подделать это - перед вызовом входа в систему, указанным выше, сделайте следующее:
user.backend = 'django.contrib.auth.backends.ModelBackend'
Другие советы
Ответ Дэниела очень хорош.
Другой способ сделать это — создать HashModelBackend после бэкэндов пользовательской авторизации. https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#writing-an-authentication-backend так:
class HashModelBackend(object):
def authenticate(self, hash=None):
user = get_user_from_hash(hash)
return user
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
И затем установите это в своих настройках:
AUTHENTICATION_BACKENDS = (
'myproject.backends.HashModelBackend',
'django.contrib.auth.backends.ModelBackend',
)
Тогда ваше мнение будет примерно таким:
def activate_account(request, hash):
user = authenticate(hash=hash)
if user:
# check if user is_active, and any other checks
login(request, user)
else:
return user_not_found_bad_hash_message
Начиная с Django 1.10, процесс был упрощен.
Во всех версиях Django, чтобы пользователь мог войти в систему, он должен быть аутентифицирован одним из серверов вашего приложения (под контролем AUTHENTICATION_BACKENDS
параметр).
Если вы просто хотите принудительно войти в систему, вы можете просто заявить, что пользователь был аутентифицирован первым сервером из этого списка:
from django.conf import settings
from django.contrib.auth import login
# Django 1.10+
login(request, user, backend=settings.AUTHENTICATION_BACKENDS[0])
# Django <1.10 - fake the authenticate() call
user.backend = settings.AUTHENTICATION_BACKENDS[0]
login(request, user)
Ответ на Дэнответ.
Способ написания вашего бэкэнда:
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
class HashModelBackend(ModelBackend):
def authenticate(self, username=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
return user
except UserModel.DoesNotExist:
return None
Ответ основан на django.contrib.auth.backends.ModelBackend исходный код.Это актуально для Джанго 1.9.
И я бы предпочел разместить собственный бэкэнд ниже стандартного в django:
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'yours.HashModelBackend',
]
потому что активация учетной записи менее возможна, чем сам вход в систему.В соответствии с https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#specifying-authentication-backends:
Порядок AUTHENTICATION_BACKENDS имеет значение, поэтому, если одно и то же имя пользователя и пароль действительны в нескольких бэкэндах, Django прекратит обработку при первом положительном совпадении.
Будь остороженэтот код будет аутентифицировать ваших пользователей даже с неправильными паролями.
Вы можете использовать ska
пакет, в котором реализован вход в Django без пароля. ska
работает с токенами аутентификации, и его безопасность основана на SHARED_KEY, который должен быть одинаковым для всех участвующих сторон (серверов).
На стороне клиента (сторона, которая запрашивает вход без пароля) вы создаете URL-адрес и подписываете его, используя ska
.Пример:
from ska import sign_url
from ska.contrib.django.ska.settings import SECRET_KEY
server_ska_login_url = 'https://server-url.com/ska/login/'
signed_url = sign_url(
auth_user='test_ska_user_0',
secret_key=SECRET_KEY,
url=server_ska_login_url
extra={
'email': 'john.doe@mail.example.com',
'first_name': 'John',
'last_name': 'Doe',
}
)
Срок действия токена по умолчанию составляет 600 секунд.Вы можете настроить это, доказав lifetime
аргумент.
На стороне сервера (сайта, на который заходят пользователи), имея в виду, что у вас установлена ska
Правильно, пользователь вошел в систему при посещении URL -адреса, если он существовал (соответствие имени пользователя) или иным образом - создан.Есть 3 обратных вызова, которые вы можете настроить в настройках Django вашего проекта.
USER_GET_CALLBACK
(нить):Вызывается, если пользователь был успешно извлечен из базы данных (существующий пользователь).USER_CREATE_CALLBACK
(нить):Запускается сразу после создания пользователя (пользователь не существовал).USER_INFO_CALLBACK
(нить):Срабатывает при успешной аутентификации.
Посмотрите документацию (http://pythonhosted.org/ska/) для большего.