Django REST框架用户注册隐私问题:寻找最佳实践,如果给定电子邮件的用户已经存在,则不显示异常



我很惊讶,我在网上没有发现任何关于以下问题的信息,我认为这应该是常见的问题?我可能只是使用了错误的搜索词,所以我很高兴收到更多信息的链接。

我的问题是,当使用ACCOUNT_EMAIL_VERIFICATION="强制"时,我不想给任何用户提供线索,除了电子邮件地址的所有者,无论该邮件是否在我的网站上注册,即不显示";用户已使用此电子邮件地址注册"如果输入了现有的电子邮件。

我的假设是,这将要求注册端点返回相同的响应,而与电子邮件是否存在无关。我看到了几种可能的方法,但似乎没有一种是好的:

  1. 使用自定义异常处理程序从发送的错误消息中删除有问题的异常。这意味着我必须在发送的所有错误消息中以某种方式识别上述异常,这样我才能在响应中保留其他异常。我想我必须通过一个字符串来识别异常消息——实际的错误消息(可能取决于语言设置?(。如果有多条错误消息,我可以简单地删除有问题的消息。但是,如果异常是唯一的异常,我就必须伪造成功创建用户后给出的相同响应。这听起来很麻烦,对我来说并不稳健。

  2. 在调用is_valid((并伪造成功响应之前,请检查唯一性。但是,我将无法返回可能添加错误的异常。

  3. 从DB中删除唯一约束,这样is_valid((方法就不会引发错误,并阻止实例保存在perform_create((中。但我并不想删除数据库级别的保护层。

我希望一定有更好的解决方案?

感谢您的帮助!Mike

您应该将错误/验证消息更改为更通用的消息,例如:

Email address error.

这与登录时的情况非常相似。你没有明确写下电子邮件地址不存在或密码太短,你只是发送了一条消息:

Invalid email or password.

此外,您还可以添加信息,如果问题再次出现,请与系统/服务管理员联系。然后,如果一个人因电子邮件问题联系了管理员,则可以手动解决问题。

生成唯一电子邮件地址的解决方案可能过于复杂,可能会带来意想不到的问题。如果用户忘记了旧帐户,重新创建了新帐户,并且丢失了以前帐户的数据,该怎么办。

我今天提出了一个可能的解决方案。看起来有点即兴,但避免了上述问题。很乐意听取您的想法或建议。

方法是覆盖create方法,如果它不能满足唯一性约束,则生成一个具有修改后的电子邮件地址的伪序列化程序实例,该地址将是唯一的,并且只从该伪实例返回错误。

此外,整个创建请求只返回HTTP200OK状态,与是否创建了用户或是否存在具有该邮件的用户无关。

#custom create method to not return "email exists" error to user if email exists
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
try: #try if data is valid. If so, create user.
serializer.is_valid(raise_exception=True)
user = self.perform_create(serializer)
print('User created:')
print(user)
except ValidationError as err: #if Validation error was returned
email = request.data['email']
email = get_adapter().clean_email(email)
# check if one issue was due to existing email
if allauth_settings.UNIQUE_EMAIL and email and email_address_exists(email):
# generate unique version of the mail address by appending string to local part to revalidate with unique mail address
provisional_email = make_email_unique(email, uniqueness_validator=email_address_exists)
# create fake request.data dict with unique mail address
provisional_request_data = request.data.copy()
provisional_request_data['email'] = provisional_email
#get new serializer with new request.data
provisional_serializer = self.get_serializer(data=provisional_request_data)
#check if data was valid if email was unique
try:
provisional_serializer.is_valid(raise_exception=True)
# get user who owns original email from request
user = get_user_from_email(request.data['email'])
except ValidationError as err2:
# else validate again, this time return any errors that may occur even with unique email
raise err2
else: #if error was not (also) due to existing mail problem raise validation errrors
raise err
headers = self.get_success_headers(serializer.data)
# always return 200 OK if no error is shown (i. e. no 201 CREATED that could hint to an existing mail address)
return Response(status=status.HTTP_200_OK,
headers=headers)

相关内容

最新更新