我希望你能帮助我找出使用密码实现手动(服务器端启动)登录而不使用的最佳方式。让我来解释的工作流程:手动登录没有密码的用户
- 用户注册
- 谢谢!与激活链接的电子邮件已经发送blablabla
- (账户现在存在,但被标记为未启用)
- 用户打开邮件,点击链接
- (帐户启用)
- 谢谢!您现在可以使用该网站
我想要做的是在用户点击邮件链接后登录,以便他可以立即开始使用该网站。
我不能使用他的密码,因为它在数据库中加密,是编写自定义身份验证后端的唯一选项吗?
我希望你能帮助我找出使用密码实现手动(服务器端启动)登录而不使用的最佳方式。让我来解释的工作流程:手动登录没有密码的用户
我想要做的是在用户点击邮件链接后登录,以便他可以立即开始使用该网站。
我不能使用他的密码,因为它在数据库中加密,是编写自定义身份验证后端的唯一选项吗?
您不需要密码即可登录用户。auth.login
function只需要一个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'
Daniel的答案非常好。
另一种方法是创建这样的自定义授权后端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': '[email protected]',
'first_name': 'John',
'last_name': 'Doe',
}
)
标记的默认生存期为600秒。您可以通过证明lifetime
参数来自定义该参数。
在服务器端(用户登录的站点),考虑到您已正确安装ska
,用户 在访问URL(如果它们存在(用户名匹配)或以其他方式创建时已登录) 。您可以在项目的Django设置中自定义3个回调。
USER_GET_CALLBACK(string):如果成功从数据库(现有用户)获取用户,则触发。 USER_CREATE_CALLBACK(字符串):在创建用户(用户不存在)后立即触发。 USER_INFO_CALLBACK(string):成功验证后触发。
有关更多信息,请参阅文档(http://pythonhosted.org/ska/)。
回应和的回答。
写你的后端道:
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源代码。这是实际的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:
AUTHENTICATION_BACKENDS事项的顺序,因此,如果同样的用户名和密码在多个后端有效,Django会在第一次正面比赛停止处理。
注意 这段代码甚至不正确的密码验证用户。
这段代码中有语法错误,所以不清楚应该发生什么('hash'被定义但未被使用,'username'被使用但未被定义)。 – 2016-08-16 10:15:32
@ amichai-schreiber谢谢!我已经更正了答案 – 2016-08-17 12:59:27
从Django 1.10开始,过程已经简化。
在所有版本的Django中,为了让用户登录,它们必须是authenticated by one of your app's backends(由AUTHENTICATION_BACKENDS
设置控制)。
如果你只是想强行登陆,你可以要求用户通过从该列表中的第一个后端认证:
from django.conf import settings
from django.contrib.auth import login
# Django 1.10+
login(request, user, backend=settings.settings.AUTHENTICATION_BACKENDS[0])
# Django <1.10 - fake the authenticate() call
user.backend = settings.AUTHENTICATION_BACKENDS[0]
login(request, user)
感谢;文档同意,但也有以下警告: “首先调用authenticate() 当您手动登录用户时,必须在调用login()之前调用authenticate()。authenticate()在用户身上设置一个属性,说明哪个验证后端成功验证了该用户(请参阅后端文档以了解详细信息),并且稍后在登录过程中需要此信息。“ 这可能是一个问题吗? – Agos 2010-05-07 10:18:39
查看我的更新 – 2010-05-07 10:28:48
尽管从django.contrib.conf导入设置并分配settings.AUTHENTICATION_BACKENDS更好,以防使用自定义后端。 – Arsham 2014-09-24 14:29:25