Commit 56519354 authored by 八千流's avatar 八千流 Committed by 老广

Email reset password (#2547)

* [Update]更改英文登录界面标题,可两行

* [Update] 更改用户通过邮箱修改密码后,该链接就失效

* [Update]更改页面左上角logo_text图片

* [Update] 优化发送邮箱改密连接失效代码

* [Update] 优化发送邮箱改密连接失效代码(2)

* [Update] 优化发送邮箱改密连接失效代码(3)

* [Update] 更新interface一键恢复默认的翻译

* [Update] 更改登录失败 用户名密码错误信息的翻译

* [Update] 优化生成token并设置缓存的代码
parent 78e4e13f
......@@ -14,6 +14,14 @@ class UserLoginForm(AuthenticationForm):
max_length=128, strip=False
)
error_messages = {
'invalid_login': _(
"Please enter a correct username and password. Note that both "
"fields may be case-sensitive."
),
'inactive': _("This account is inactive."),
}
def confirm_login_allowed(self, user):
if not user.is_staff:
raise forms.ValidationError(
......
......@@ -52,7 +52,7 @@
</style>
</head>
<body style="height: 100%">
<body style="height: 100%;font-size: 13px">
<div>
<div class="box-1">
<div class="box-2">
......@@ -60,19 +60,19 @@
</div>
<div class="box-3">
<div style="background-color: white">
<div style="margin-top: 40px;padding-top: 50px;">
<span style="font-size: 24px;font-weight:400;color: #151515;letter-spacing: 0;">{{ JMS_TITLE }}</span>
<div style="margin-top: 30px;padding-top: 40px;padding-left: 20px;padding-right: 20px;height: 80px">
<span style="font-size: 21px;font-weight:400;color: #151515;letter-spacing: 0;">{{ JMS_TITLE }}</span>
</div>
<div style="font-size: 12px;color: #999999;letter-spacing: 0;line-height: 18px;margin-top: 10px">
<div style="font-size: 12px;color: #999999;letter-spacing: 0;line-height: 18px;margin-top: 18px">
{% trans 'Welcome back, please enter username and password to login' %}
</div>
<div style="margin-bottom: 10px">
<div>
<div class="col-md-1"></div>
<div class="contact-form col-md-10" style="margin-top: 20px;height: 35px">
<div class="contact-form col-md-10" style="margin-top: 10px;height: 35px">
<form id="contact-form" action="" method="post" role="form" novalidate="novalidate">
{% csrf_token %}
<div style="height: 48px;color: red">
<div style="height: 45px;color: red;line-height: 17px;">
{% if block_login %}
<p class="red-fonts">{% trans 'Log in frequently and try again later' %}</p>
{% elif password_expired %}
......@@ -92,7 +92,7 @@
<div class="form-group">
<input type="password" class="form-control" name="{{ form.password.html_name }}" placeholder="{% trans 'Password' %}" required="">
</div>
<div class="form-group" style="height: 50px;margin-bottom: 0">
<div class="form-group" style="height: 50px;margin-bottom: 0;font-size: 13px">
{{ form.captcha }}
</div>
<div class="form-group" style="margin-top: 10px">
......
This diff is collapsed.
......@@ -3,24 +3,28 @@
#
import uuid
import base64
import string
import random
from collections import OrderedDict
from django.conf import settings
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import AbstractUser
from django.core import signing
from django.core.cache import cache
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.shortcuts import reverse
from common.utils import get_signer, date_expired_default
from common.utils import get_signer, date_expired_default, get_logger
__all__ = ['User']
signer = get_signer()
logger = get_logger(__file__)
class User(AbstractUser):
ROLE_ADMIN = 'Admin'
......@@ -47,6 +51,9 @@ class User(AbstractUser):
(SOURCE_OPENID, 'OpenID'),
(SOURCE_RADIUS, 'Radius'),
)
CACHE_KEY_USER_RESET_PASSWORD_PREFIX = "_KEY_USER_RESET_PASSWORD_{}"
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
username = models.CharField(
max_length=128, unique=True, verbose_name=_('Username')
......@@ -346,9 +353,32 @@ class User(AbstractUser):
return user_default
def generate_reset_token(self):
return signer.sign_t(
{'reset': str(self.id), 'email': self.email}, expires_in=3600
)
letter = string.ascii_letters + string.digits
token =''.join([random.choice(letter) for _ in range(50)])
self.set_cache(token)
return token
def set_cache(self, token):
key = self.CACHE_KEY_USER_RESET_PASSWORD_PREFIX.format(token)
cache.set(key, {'id': self.id, 'email': self.email}, 3600)
@classmethod
def validate_reset_password_token(cls, token):
try:
key = cls.CACHE_KEY_USER_RESET_PASSWORD_PREFIX.format(token)
value = cache.get(key)
user_id = value.get('id', '')
email = value.get('email', '')
user = cls.objects.get(id=user_id, email=email)
except (AttributeError, cls.DoesNotExist) as e:
logger.error(e, exc_info=True)
user = None
return user
@classmethod
def expired_reset_password_token(cls, token):
key = cls.CACHE_KEY_USER_RESET_PASSWORD_PREFIX.format(token)
cache.delete(key)
@property
def otp_enabled(self):
......@@ -400,18 +430,6 @@ class User(AbstractUser):
access_key = app.create_access_key()
return app, access_key
@classmethod
def validate_reset_token(cls, token):
try:
data = signer.unsign_t(token)
user_id = data.get('reset', None)
user_email = data.get('email', '')
user = cls.objects.get(id=user_id, email=user_email)
except (signing.BadSignature, cls.DoesNotExist):
user = None
return user
def reset_password(self, new_password):
self.set_password(new_password)
self.date_password_last_updated = timezone.now()
......
# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
from django.core.cache import cache
from django.shortcuts import render
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import RedirectView
......@@ -84,7 +85,7 @@ class UserResetPasswordView(TemplateView):
def get(self, request, *args, **kwargs):
token = request.GET.get('token', '')
user = User.validate_reset_token(token)
user = User.validate_reset_password_token(token)
if not user:
kwargs.update({'errors': _('Token invalid or expired')})
else:
......@@ -100,12 +101,12 @@ class UserResetPasswordView(TemplateView):
if password != password_confirm:
return self.get(request, errors=_('Password not same'))
user = User.validate_reset_token(token)
user = User.validate_reset_password_token(token)
if not user:
return self.get(request, errors=_('Token invalid or expired'))
if not user.can_update_password():
error = _('User auth from {}, go there change password'.format(user.source))
return self.get(request, errors=error)
if not user:
return self.get(request, errors=_('Token invalid or expired'))
is_ok = check_password_rules(password)
if not is_ok:
......@@ -115,6 +116,7 @@ class UserResetPasswordView(TemplateView):
)
user.reset_password(password)
User.expired_reset_password_token(token)
return HttpResponseRedirect(reverse('users:reset-password-success'))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment