我希望您能帮助我找到实现手动(服务器端启动)登录的最佳方式,而无需使用密码。让我解释一下工作流程:
我要做的是在用户点击电子邮件链接后登录用户,以便他可以立即开始使用该网站。
我无法使用他的密码,因为它是在DB中加密的,是编写自定义身份验证后端的唯一选择吗?
答案 0 :(得分:87)
您不需要密码来记录用户。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'
答案 1 :(得分:25)
丹尼尔的回答非常好。
另一种方法是在自定义授权后端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
答案 2 :(得分:23)
自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.AUTHENTICATION_BACKENDS[0])
# Django <1.10 - fake the authenticate() call
user.backend = settings.AUTHENTICATION_BACKENDS[0]
login(request, user)
答案 3 :(得分:2)
你可以使用ska
包,它实现了对Django的无密码登录。 ska
与身份验证令牌配合使用,其安全性基于SHARED_KEY,对于所涉及的所有各方(服务器),它应该相同。
在客户端(请求无密码登录的一方),您使用ska
生成一个URL并对其进行签名。例如:
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/)。
答案 4 :(得分:2)
回应 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.contrib.auth.backends.ModelBackend 源代码。对于django 1.9来说这是实际的。
我宁愿将自定义后端放在django的默认值下面:
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'yours.HashModelBackend',
]
因为帐户激活不如登录本身。根据{{3}}:
AUTHENTICATION_BACKENDS的顺序很重要,因此如果相同的用户名和密码在多个后端有效,Django将在第一次正面匹配时停止处理。
小心 即使密码不正确,此代码也会对您的用户进行身份验证