忘记密码后,重置密码的逻辑
逻辑:
主要是借鉴了Django内置的重置密码的逻辑。
1、如果忘记密码,用户填写注册时的邮箱;
2、根据邮箱,得到用户User object,并生成uidb64和token(用户加密);
3、将得到的重置密码链接发到邮箱;
4、用户根据得到的链接填写新密码;
1,2步骤
主要是根据注册邮箱得到重置密码链接。源代码:
class ForgetPasswdView(FormView):
template_name = 'account/forgetpasswd.html'
form_class = UserPasswordResetForm
success_url = '/'
def form_valid(self, form):
try:
form.send()
except ValidationError,e:
form.add_error('email', e)
form._clean_form()
return self.render_to_response(self.get_context_data(form=form))
return HttpResponse('check email')
class UserPasswordResetForm(PasswordResetForm):
def send(self):
email = self.cleaned_data['email']
DOMAIN = settings.DOMAIN
DOMAIN = DOMAIN.rstrip('/')
token_generator = default_token_generator
if len(list(self.get_users(email))) == 0:
raise forms.ValidationError('user not exists')
for user in self.get_users(email):
uid = urlsafe_base64_encode(force_bytes(user.id))
token = token_generator.make_token(user)
message = "\n".join([
'您的用户名是:{0}'.format(user.username),
'请访问该链接,进行密码重置:',
'/'.join([DOMAIN, 'account/resetpwd', uid, token]) + '/',
])
send_mail('注册用户密码重置', message, None, [email])
上面一个是类视图,一个是Form类。类视图只写基本逻辑,具体处理部分写在form类中。代码中form.get_users(email)会根据邮箱得到用户类,Django中的源代码如下:
class PasswordResetForm(forms.Form):
email = forms.EmailField(label=_("Email"), max_length=254)
def get_users(self, email):
"""Given an email, return matching user(s) who should receive a reset.
This allows subclasses to more easily customize the default policies
that prevent inactive users and users with unusable passwords from
resetting their password.
"""
active_users = get_user_model()._default_manager.filter(
email__iexact=email, is_active=True)
return (u for u in active_users if u.has_usable_password())
得到用户后,通过用户类,生成uid和token。并将相应链接发到注册的邮箱。
3、收到的邮件:
邮件内容:
您的用户名是:hbnnlong
请访问该链接,进行密码重置:
http://hbnnforever.cn/account/resetpwd/Mg/4ck-854a0f660ddf/
Mg就是用户id经过编码后的字符串,后面的即为token。我设定了token的有效期是1天。
4、用户访问链接进行重置密码
def user_decorator(method):
def wrapper(instance,request, *args, **kwargs):
token_generator = default_token_generator
UserModel = get_user_model()
uidb64, token = instance.kwargs['uidb64'], instance.kwargs['token']
assert uidb64 is not None and token is not None
try:
uid = urlsafe_base64_decode(uidb64)
user = UserModel._default_manager.get(pk=uid)
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
user = None
if user is not None and token_generator.check_token(user, token):
instance.request.user = user
return method(instance,request, *args, **kwargs)
else:
return HttpResponse('link expires')
return wrapper
class ResetPasswdView(FormView):
template_name = 'account/resetpwd.html'
form_class = SetPasswordForm
success_url = '/'
@user_decorator
def get(self, request, *args, **kwargs):
return super(ResetPasswdView,self).get(request, *args, **kwargs)
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
return form_class(self.request.user, **self.get_form_kwargs())
def form_valid(self, form):
form.save()
return HttpResponseRedirect('/account/login/')
@user_decorator
def post(self, request, *args, **kwargs):
return super(ResetPasswdView,self).post(request,*args,**kwargs)
在上面,我写了一个装饰器,因为SetPasswordForm需要传入当前的User,那对于GET和POST请求都需要,因此为了避免代码重复,我就写了一个装饰器user_decorator,用来获取user。
这个装饰器与普通的函数装饰器不同,它是一个类方法的装饰器,参数一定要带上代表实例本身的参数,比如我用了instance。其实,Django自己还有一个将函数装饰器转为类方法的装饰器:method_decorator。
上面就是整个重置密码的逻辑。
--------EOF---------
微信分享/微信扫码阅读
微信分享/微信扫码阅读
