手动登录没有密码的用户

我希望您能帮助我找到使用密码实现手动(服务器端启动)登录 没有的最佳方法。让我来解释一下工作流程:

  • 用户注册表
  • 谢谢! 一封带有激活链接的电子邮件已经被发送了
  • (帐户现已存在,但标记为未启用)
  • 用户打开电子邮件,点击链接
  • (启用帐户)
  • 谢谢! 您现在可以使用该网站

我正在尝试做的是登录用户后,他已经点击电子邮件链接,使他可以开始使用该网站立即。

我不能使用他的密码,因为它在数据库加密,是唯一的选择写一个自定义身份验证后端?

41319 次浏览

登录用户不需要密码。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'

丹尼尔的回答很好。

另一种方法是在自定义授权后端 https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#writing-an-authentication-backend之后创建一个 HashModelBackend,如下所示:

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

您可以使用 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 时登录。您可以在项目的 Django 设置中自定义3个回调。

  • USER_GET_CALLBACK(字符串) : 如果用户从数据库(现有用户)成功获取,则激发。
  • USER_CREATE_CALLBACK(字符串) : 在创建用户后立即激活(用户不存在)。
  • USER_INFO_CALLBACK(字符串) : 在成功身份验证后激发。

有关更多信息,请参见文档(http://pythonhosted.org/ska/)。

回应 Dan的回答。

编写后台程序的一种方法:

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 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:

AUTHENTATION _ BACKENDS 的顺序很重要,因此如果相同的用户名和密码在多个后端中有效,Django 将在第一次正匹配时停止处理。

小心点 即使使用不正确的密码,此代码也会验证您的用户。

从 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)