From 6f21b5ad7d3be919e57141f638a3b8912c2f585f Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 12 Apr 2024 20:42:36 -0400 Subject: [PATCH] login code via email --- boofilsic/settings.py | 1 + common/templates/common/verify.html | 52 +++++++++++++++++++++++++++++ requirements.txt | 2 +- users/account.py | 51 +++++++++++++++++++++++++--- users/models/user.py | 4 +++ users/templates/users/login.html | 10 +++++- users/urls.py | 1 + 7 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 common/templates/common/verify.html diff --git a/boofilsic/settings.py b/boofilsic/settings.py index c7d4ad9f..9a0afe5a 100644 --- a/boofilsic/settings.py +++ b/boofilsic/settings.py @@ -358,6 +358,7 @@ TEMPLATES = [ WSGI_APPLICATION = "boofilsic.wsgi.application" SESSION_COOKIE_NAME = "neodbsid" +SESSION_COOKIE_AGE = 90 * 24 * 60 * 60 # 90 days AUTHENTICATION_BACKENDS = [ "mastodon.auth.OAuth2Backend", diff --git a/common/templates/common/verify.html b/common/templates/common/verify.html new file mode 100644 index 00000000..40b0135e --- /dev/null +++ b/common/templates/common/verify.html @@ -0,0 +1,52 @@ +{% load static %} +{% load i18n %} +{% load l10n %} +{% load admin_url %} +{% load mastodon %} +{% load oauth_token %} +{% load truncate %} +{% load thumb %} + + + + + + {{ site_name }} + {% include "common_libs.html" %} + + + {% include "_header.html" %} +
+
+
+

验证邮件已发送

+
+ 请点击邮件中的登录链接,或输入收到的验证码: + +
+
+ + {{ error }} +
+ + {% csrf_token %} +
+
+
+ {% include "_footer.html" %} + + diff --git a/requirements.txt b/requirements.txt index c2028e8f..415dbefb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ dateparser discord.py django~=4.2.11 django-anymail -django-auditlog>=3.0.0-beta.4 +django-auditlog>=3.0.0 django-bleach django-compressor django-cors-headers diff --git a/users/account.py b/users/account.py index 160d7312..2c226081 100644 --- a/users/account.py +++ b/users/account.py @@ -16,6 +16,7 @@ from django.db.models import Count, Q from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils import timezone +from django.utils.baseconv import base62 from django.utils.translation import gettext_lazy as _ from django.views.decorators.http import require_http_methods from loguru import logger @@ -86,18 +87,24 @@ def connect(request): {"msg": _("无效的电子邮件地址")}, ) user = User.objects.filter(email__iexact=login_email).first() + code = base62.encode(random.randint(pow(62, 4), pow(62, 5) - 1)) + cache.set(f"login_{code}", login_email, timeout=60 * 15) + request.session["login_email"] = login_email + action = "login" if user else "register" django_rq.get_queue("mastodon").enqueue( send_verification_link, user.pk if user else 0, - "login" if user else "register", + action, login_email, + code, ) return render( request, - "common/info.html", + "common/verify.html", { "msg": _("验证邮件已发送"), "secondary_msg": _("请查阅收件箱"), + "action": action, }, ) login_domain = ( @@ -284,7 +291,7 @@ class RegistrationForm(forms.ModelForm): return email -def send_verification_link(user_id, action, email): +def send_verification_link(user_id, action, email, code=""): s = {"i": user_id, "e": email, "a": action} v = TimestampSigner().sign_object(s) if action == "verify": @@ -292,9 +299,13 @@ def send_verification_link(user_id, action, email): url = settings.SITE_INFO["site_url"] + "/account/verify_email?c=" + v msg = f"你好,\n请点击以下链接验证你的电子邮件地址 {email}\n{url}\n\n如果你没有注册过本站,请忽略此邮件。" elif action == "login": - subject = f'{settings.SITE_INFO["site_name"]} - {_("登录")}' + subject = f'{settings.SITE_INFO["site_name"]} - {_("登录")} {code}' url = settings.SITE_INFO["site_url"] + "/account/login/email?c=" + v - msg = f"你好,\n请点击以下链接登录{email}账号\n{url}\n\n如果你没有请求登录本站,请忽略此邮件;如果你确信账号存在安全风险,请更改注册邮件地址或与我们联系。" + msg = ( + "你好,\n请" + + f"在登录界面输入如下验证码:\n\n{code}\n\n或" + + f"点击以下链接登录{email}账号\n{url}\n\n如果你没有请求登录本站,请忽略此邮件;如果你确信账号存在安全风险,请更改注册邮件地址或与我们联系。" + ) elif action == "register": subject = f'{settings.SITE_INFO["site_name"]} - {_("注册新账号")}' url = settings.SITE_INFO["site_url"] + "/account/register_email?c=" + v @@ -320,6 +331,36 @@ def send_verification_link(user_id, action, email): logger.error(e) +@require_http_methods(["POST"]) +def verify_code(request): + code = request.POST.get("code") + if not code: + return render( + request, + "common/verify.html", + { + "error": _("无效的验证码"), + }, + ) + login_email = cache.get(f"login_{code}") + if not login_email or request.session.get("login_email") != login_email: + return render( + request, + "common/verify.html", + { + "error": _("无效的验证码"), + }, + ) + cache.delete(f"login_{code}") + user = User.objects.filter(email__iexact=login_email).first() + if user: + resp = login_existing_user(request, user) + else: + resp = register_new_user(request, username=None, email=login_email) + resp.set_cookie("mastodon_domain", "@") + return resp + + def verify_email(request): error = "" try: diff --git a/users/models/user.py b/users/models/user.py index e768b21c..569521d7 100644 --- a/users/models/user.py +++ b/users/models/user.py @@ -31,6 +31,10 @@ _RESERVED_USERNAMES = [ "oauth2_login", "__", "admin", + "administrator", + "system", + "user", + "users", "api", "me", ] diff --git a/users/templates/users/login.html b/users/templates/users/login.html index 37725c1a..3e2a384c 100644 --- a/users/templates/users/login.html +++ b/users/templates/users/login.html @@ -85,7 +85,6 @@ id="loginButton" disabled /> - {{ sites|json_script:"sites-data" }} {% else %}