login code via email
This commit is contained in:
parent
c5e0dd5432
commit
6f21b5ad7d
7 changed files with 114 additions and 7 deletions
|
@ -358,6 +358,7 @@ TEMPLATES = [
|
||||||
WSGI_APPLICATION = "boofilsic.wsgi.application"
|
WSGI_APPLICATION = "boofilsic.wsgi.application"
|
||||||
|
|
||||||
SESSION_COOKIE_NAME = "neodbsid"
|
SESSION_COOKIE_NAME = "neodbsid"
|
||||||
|
SESSION_COOKIE_AGE = 90 * 24 * 60 * 60 # 90 days
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
"mastodon.auth.OAuth2Backend",
|
"mastodon.auth.OAuth2Backend",
|
||||||
|
|
52
common/templates/common/verify.html
Normal file
52
common/templates/common/verify.html
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load l10n %}
|
||||||
|
{% load admin_url %}
|
||||||
|
{% load mastodon %}
|
||||||
|
{% load oauth_token %}
|
||||||
|
{% load truncate %}
|
||||||
|
{% load thumb %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{ site_name }}</title>
|
||||||
|
{% include "common_libs.html" %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% include "_header.html" %}
|
||||||
|
<main class="container">
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h3>验证邮件已发送</h3>
|
||||||
|
</header>
|
||||||
|
请点击邮件中的登录链接,或输入收到的验证码:
|
||||||
|
<style type="text/css">
|
||||||
|
.otp input {
|
||||||
|
font-family: monospace;
|
||||||
|
font-weight: bolder;
|
||||||
|
letter-spacing: 2em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<form action="{% url 'users:verify_code' %}" method="post">
|
||||||
|
<div class="otp">
|
||||||
|
<input name="code"
|
||||||
|
maxlength="5"
|
||||||
|
value=""
|
||||||
|
autocomplete="one-time-code"
|
||||||
|
autocapitalize="none"
|
||||||
|
autocorrect="off"
|
||||||
|
required
|
||||||
|
pattern="^[a-zA-Z0-9]{5}$" />
|
||||||
|
<small>{{ error }}</small>
|
||||||
|
</div>
|
||||||
|
<input type="submit" value="提交" />
|
||||||
|
{% csrf_token %}
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
{% include "_footer.html" %}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -4,7 +4,7 @@ dateparser
|
||||||
discord.py
|
discord.py
|
||||||
django~=4.2.11
|
django~=4.2.11
|
||||||
django-anymail
|
django-anymail
|
||||||
django-auditlog>=3.0.0-beta.4
|
django-auditlog>=3.0.0
|
||||||
django-bleach
|
django-bleach
|
||||||
django-compressor
|
django-compressor
|
||||||
django-cors-headers
|
django-cors-headers
|
||||||
|
|
|
@ -16,6 +16,7 @@ from django.db.models import Count, Q
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.utils.baseconv import base62
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.decorators.http import require_http_methods
|
from django.views.decorators.http import require_http_methods
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
@ -86,18 +87,24 @@ def connect(request):
|
||||||
{"msg": _("无效的电子邮件地址")},
|
{"msg": _("无效的电子邮件地址")},
|
||||||
)
|
)
|
||||||
user = User.objects.filter(email__iexact=login_email).first()
|
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(
|
django_rq.get_queue("mastodon").enqueue(
|
||||||
send_verification_link,
|
send_verification_link,
|
||||||
user.pk if user else 0,
|
user.pk if user else 0,
|
||||||
"login" if user else "register",
|
action,
|
||||||
login_email,
|
login_email,
|
||||||
|
code,
|
||||||
)
|
)
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"common/info.html",
|
"common/verify.html",
|
||||||
{
|
{
|
||||||
"msg": _("验证邮件已发送"),
|
"msg": _("验证邮件已发送"),
|
||||||
"secondary_msg": _("请查阅收件箱"),
|
"secondary_msg": _("请查阅收件箱"),
|
||||||
|
"action": action,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
login_domain = (
|
login_domain = (
|
||||||
|
@ -284,7 +291,7 @@ class RegistrationForm(forms.ModelForm):
|
||||||
return email
|
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}
|
s = {"i": user_id, "e": email, "a": action}
|
||||||
v = TimestampSigner().sign_object(s)
|
v = TimestampSigner().sign_object(s)
|
||||||
if action == "verify":
|
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
|
url = settings.SITE_INFO["site_url"] + "/account/verify_email?c=" + v
|
||||||
msg = f"你好,\n请点击以下链接验证你的电子邮件地址 {email}\n{url}\n\n如果你没有注册过本站,请忽略此邮件。"
|
msg = f"你好,\n请点击以下链接验证你的电子邮件地址 {email}\n{url}\n\n如果你没有注册过本站,请忽略此邮件。"
|
||||||
elif action == "login":
|
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
|
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":
|
elif action == "register":
|
||||||
subject = f'{settings.SITE_INFO["site_name"]} - {_("注册新账号")}'
|
subject = f'{settings.SITE_INFO["site_name"]} - {_("注册新账号")}'
|
||||||
url = settings.SITE_INFO["site_url"] + "/account/register_email?c=" + v
|
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)
|
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):
|
def verify_email(request):
|
||||||
error = ""
|
error = ""
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -31,6 +31,10 @@ _RESERVED_USERNAMES = [
|
||||||
"oauth2_login",
|
"oauth2_login",
|
||||||
"__",
|
"__",
|
||||||
"admin",
|
"admin",
|
||||||
|
"administrator",
|
||||||
|
"system",
|
||||||
|
"user",
|
||||||
|
"users",
|
||||||
"api",
|
"api",
|
||||||
"me",
|
"me",
|
||||||
]
|
]
|
||||||
|
|
|
@ -85,7 +85,6 @@
|
||||||
id="loginButton"
|
id="loginButton"
|
||||||
disabled />
|
disabled />
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">if (Cookies.get('mastodon_domain')) $('#domain').val(Cookies.get('mastodon_domain'));</script>
|
|
||||||
{{ sites|json_script:"sites-data" }}
|
{{ sites|json_script:"sites-data" }}
|
||||||
<script>
|
<script>
|
||||||
function switch_login(){
|
function switch_login(){
|
||||||
|
@ -129,6 +128,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
var d = Cookies.get('mastodon_domain');
|
||||||
|
if (d) {
|
||||||
|
if (d == "@") {
|
||||||
|
$('select').val('email');
|
||||||
|
switch_login()
|
||||||
|
} else {
|
||||||
|
$('#domain').val(Cookies.get('mastodon_domain'));
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% else %}
|
{% else %}
|
||||||
<select name="domain">
|
<select name="domain">
|
||||||
|
|
|
@ -8,6 +8,7 @@ urlpatterns = [
|
||||||
path("login/oauth", connect_redirect_back, name="login_oauth"),
|
path("login/oauth", connect_redirect_back, name="login_oauth"),
|
||||||
path("login/email", verify_email, name="login_email"),
|
path("login/email", verify_email, name="login_email"),
|
||||||
path("verify_email", verify_email, name="verify_email"),
|
path("verify_email", verify_email, name="verify_email"),
|
||||||
|
path("verify_code", verify_code, name="verify_code"),
|
||||||
path("register_email", verify_email, name="register_email"),
|
path("register_email", verify_email, name="register_email"),
|
||||||
path("register", register, name="register"),
|
path("register", register, name="register"),
|
||||||
path("connect", connect, name="connect"),
|
path("connect", connect, name="connect"),
|
||||||
|
|
Loading…
Add table
Reference in a new issue