feat: enhance password reset functionality with email verification and validation
This commit is contained in:
parent
f5166523de
commit
d7a3b7fd3f
@ -607,19 +607,96 @@ def update_user_role(instance, user):
|
|||||||
|
|
||||||
|
|
||||||
class RePasswordSerializer(serializers.Serializer):
|
class RePasswordSerializer(serializers.Serializer):
|
||||||
password = serializers.CharField(required=True, label=_("Password"),
|
email = serializers.EmailField(
|
||||||
validators=[validators.RegexValidator(regex=re.compile(
|
required=True,
|
||||||
"^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z_!@#$%^&*`~.()-+=]+$)(?![a-z0-9]+$)(?![a-z_!@#$%^&*`~()-+=]+$)"
|
label=_("Email"),
|
||||||
"(?![0-9_!@#$%^&*`~()-+=]+$)[a-zA-Z0-9_!@#$%^&*`~.()-+=]{6,20}$")
|
validators=[validators.EmailValidator(message=ExceptionCodeConstants.EMAIL_FORMAT_ERROR.value.message,
|
||||||
, message=_(
|
code=ExceptionCodeConstants.EMAIL_FORMAT_ERROR.value.code)])
|
||||||
"The confirmation password must be 6-20 characters long and must be a combination of letters, numbers, and special characters."))])
|
|
||||||
|
|
||||||
re_password = serializers.CharField(required=True, label=_("Confirm Password"),
|
code = serializers.CharField(required=True, label=_("Code"))
|
||||||
validators=[validators.RegexValidator(regex=re.compile(
|
password = serializers.CharField(
|
||||||
"^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z_!@#$%^&*`~.()-+=]+$)(?![a-z0-9]+$)(?![a-z_!@#$%^&*`~()-+=]+$)"
|
required=True,
|
||||||
"(?![0-9_!@#$%^&*`~()-+=]+$)[a-zA-Z0-9_!@#$%^&*`~.()-+=]{6,20}$")
|
label=_("Password"),
|
||||||
, message=_(
|
max_length=20,
|
||||||
"The confirmation password must be 6-20 characters long and must be a combination of letters, numbers, and special characters."))]
|
min_length=6,
|
||||||
|
validators=[
|
||||||
|
validators.RegexValidator(
|
||||||
|
regex=PASSWORD_REGEX,
|
||||||
|
message=_(
|
||||||
|
"The password must be 6-20 characters long and must be a combination of letters, numbers, and special characters."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
re_password = serializers.CharField(
|
||||||
|
required=True,
|
||||||
|
label=_("Re Password"),
|
||||||
|
validators=[
|
||||||
|
validators.RegexValidator(
|
||||||
|
regex=PASSWORD_REGEX,
|
||||||
|
message=_(
|
||||||
|
"The confirmation password must be 6-20 characters long and must be a combination of letters, numbers, and special characters."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
def is_valid(self, *, raise_exception=False):
|
||||||
|
super().is_valid(raise_exception=True)
|
||||||
|
email = self.data.get("email")
|
||||||
|
cache_code = cache.get(get_key(email + ':reset_password'), version=version)
|
||||||
|
if self.data.get('password') != self.data.get('re_password'):
|
||||||
|
raise AppApiException(ExceptionCodeConstants.PASSWORD_NOT_EQ_RE_PASSWORD.value.code,
|
||||||
|
ExceptionCodeConstants.PASSWORD_NOT_EQ_RE_PASSWORD.value.message)
|
||||||
|
if cache_code != self.data.get('code'):
|
||||||
|
raise AppApiException(ExceptionCodeConstants.CODE_ERROR.value.code,
|
||||||
|
ExceptionCodeConstants.CODE_ERROR.value.message)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def reset_password(self):
|
||||||
|
"""
|
||||||
|
修改密码
|
||||||
|
:return: 是否成功
|
||||||
|
"""
|
||||||
|
if self.is_valid():
|
||||||
|
email = self.data.get("email")
|
||||||
|
QuerySet(User).filter(email=email).update(
|
||||||
|
password=password_encrypt(self.data.get('password')))
|
||||||
|
code_cache_key = email + ":reset_password"
|
||||||
|
cache.delete(get_key(code_cache_key), version=version)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ResetCurrentUserPassword(serializers.Serializer):
|
||||||
|
password = serializers.CharField(
|
||||||
|
required=True,
|
||||||
|
label=_("Password"),
|
||||||
|
max_length=20,
|
||||||
|
min_length=6,
|
||||||
|
validators=[
|
||||||
|
validators.RegexValidator(
|
||||||
|
regex=PASSWORD_REGEX,
|
||||||
|
message=_(
|
||||||
|
"The password must be 6-20 characters long and must be a combination of letters, numbers, and special characters."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
re_password = serializers.CharField(
|
||||||
|
required=True,
|
||||||
|
label=_("Re Password"),
|
||||||
|
validators=[
|
||||||
|
validators.RegexValidator(
|
||||||
|
regex=PASSWORD_REGEX,
|
||||||
|
message=_(
|
||||||
|
"The confirmation password must be 6-20 characters long and must be a combination of letters, numbers, and special characters."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@ -28,7 +28,7 @@ from users.api.user import UserProfileAPI, TestWorkspacePermissionUserApi, Delet
|
|||||||
SendEmailAPI, CheckCodeAPI, SwitchUserLanguageAPI
|
SendEmailAPI, CheckCodeAPI, SwitchUserLanguageAPI
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from users.serializers.user import UserProfileSerializer, UserManageSerializer, CheckCodeSerializer, \
|
from users.serializers.user import UserProfileSerializer, UserManageSerializer, CheckCodeSerializer, \
|
||||||
SendEmailSerializer, RePasswordSerializer, SwitchLanguageSerializer
|
SendEmailSerializer, RePasswordSerializer, SwitchLanguageSerializer, ResetCurrentUserPassword
|
||||||
|
|
||||||
default_password = CONFIG.get('DEFAULT_PASSWORD', 'MaxKB@123..')
|
default_password = CONFIG.get('DEFAULT_PASSWORD', 'MaxKB@123..')
|
||||||
|
|
||||||
@ -260,6 +260,7 @@ class UserManage(APIView):
|
|||||||
@log(menu='User management', operate='Change password',
|
@log(menu='User management', operate='Change password',
|
||||||
get_operation_object=lambda r, k: get_user_operation_object(k.get('user_id')),
|
get_operation_object=lambda r, k: get_user_operation_object(k.get('user_id')),
|
||||||
get_details=get_re_password_details)
|
get_details=get_re_password_details)
|
||||||
|
@has_permissions(PermissionConstants.USER_EDIT, RoleConstants.ADMIN)
|
||||||
def put(self, request: Request, user_id):
|
def put(self, request: Request, user_id):
|
||||||
return result.success(
|
return result.success(
|
||||||
UserManageSerializer.Operate(data={'id': user_id}).re_password(request.data, with_valid=True))
|
UserManageSerializer.Operate(data={'id': user_id}).re_password(request.data, with_valid=True))
|
||||||
@ -293,10 +294,9 @@ class RePasswordView(APIView):
|
|||||||
@log(menu='User management', operate='Change password',
|
@log(menu='User management', operate='Change password',
|
||||||
get_operation_object=lambda r, k: {'name': r.user.username},
|
get_operation_object=lambda r, k: {'name': r.user.username},
|
||||||
get_details=get_re_password_details)
|
get_details=get_re_password_details)
|
||||||
@has_permissions(PermissionConstants.USER_EDIT, RoleConstants.ADMIN)
|
|
||||||
def post(self, request: Request):
|
def post(self, request: Request):
|
||||||
serializer_obj = RePasswordSerializer(data=request.data)
|
serializer_obj = RePasswordSerializer(data=request.data)
|
||||||
return result.success(serializer_obj.reset_password(request.user.id))
|
return result.success(serializer_obj.reset_password())
|
||||||
|
|
||||||
|
|
||||||
class SendEmail(APIView):
|
class SendEmail(APIView):
|
||||||
@ -367,7 +367,7 @@ class ResetCurrentUserPasswordView(APIView):
|
|||||||
@has_permissions(PermissionConstants.CHANGE_PASSWORD, RoleConstants.ADMIN, RoleConstants.USER,
|
@has_permissions(PermissionConstants.CHANGE_PASSWORD, RoleConstants.ADMIN, RoleConstants.USER,
|
||||||
RoleConstants.WORKSPACE_MANAGE)
|
RoleConstants.WORKSPACE_MANAGE)
|
||||||
def post(self, request: Request):
|
def post(self, request: Request):
|
||||||
serializer_obj = RePasswordSerializer(data=request.data)
|
serializer_obj = ResetCurrentUserPassword(data=request.data)
|
||||||
if serializer_obj.reset_password(request.user.id):
|
if serializer_obj.reset_password(request.user.id):
|
||||||
version, get_key = Cache_Version.TOKEN.value
|
version, get_key = Cache_Version.TOKEN.value
|
||||||
cache.delete(get_key(token=request.auth), version=version)
|
cache.delete(get_key(token=request.auth), version=version)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user