1、使用django自带功能实现登录/退出登录

 使用django自带登录功能,前提生成用户(用户注册)使用的是django自带的user,或称models中用户表继承于django自带的user

1.1、登录

 views.py:

from django.contrib.auth import authenticate,login,logout

def acc_login(request):
"""登录页面"""
error_msg = ''
if request.method == "POST":
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username = username, password = password) if user:
login(request,user)
return redirect(request.GET.get('next','/index/')) # 如果有next则跳转到next指定的页面,如果没有则跳转到index页面 else:
error_msg = "Wrong username or password!" return render(request,"login.html",{'error_msg':error_msg})

1.2、退出登录

 views.py:

def acc_logout(request):
logout(request)
return redirect("/login/")

 urls.py:

from django.urls import path
from NBCRM import views urlpatterns = [ path('login/',views.acc_login),
path('logout/',views.acc_logout,name="logout"), ]

 settings.py:

  当某些页面设置了登录才能访问时,用户访问该页面会失败,此时可以在settings中进行下面的设置,指定用户在未登录前访问需登录才能访问的页面时,跳转到指定(登录)页面,执行某些操作,成功后才能访问目标页面。

LOGIN_URL = '/login/'

 登录界面:

 


2.自定义登录方式

1)login相关代码:

def login(request):
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password") user = models.User.objects.filter(username=username, password=password) # [User Obj, ]
if user:
# 登陆成功
request.session["is_login"] = ""
# request.session["username"] = username
request.session["user_id"] = user[0].id
# 1. 生成特殊的字符串
# 2. 特殊字符串当成key,在数据库的session表中对应一个session value
# 3. 在响应中向浏览器写了一个Cookie Cookie的值就是 特殊的字符串 return redirect("/index/") return render(request, "login.html")

2)check_login:

 装饰器,用于检查用户是否登录

from functools import wraps
def check_login(f):
@wraps(f)
def inner(request, *args, **kwargs):
if request.session.get("is_login") == "":
return f(request, *args, **kwargs)
else:
return redirect("/login/")
return inner

3)index:

 首页,访问前判断用户是否已登录,登录则成功访问,未登录则跳转登录页面

@check_login
def index(request):
user_id = request.session.get("user_id")
# 根据id去数据库中查找用户
user_obj = models.User.objects.filter(id=user_id)
if user_obj:
return render(request, "index.html", {"user": user_obj[0]})
else:
return render(request, "index.html", {"user": "匿名用户"})

2.1、session简单介绍

1)session作用

  1. 生成随机字符串
  2. 写到用户浏览器的cookie中
  3. 保存到session中
  4. 在随机字符串对应的字典中设置相关内容

2)session默认过期时间为2周,如果自己设置过期时间,自定义设置过期时间优先级高于默认时间

request.session.set_expiry(value)  # 设置session过期时间

 默认的过期时间是两周,如果自己设置了过期时间,这样自己设定的优先级就会高于默认的

 如果value是个整数,session会在些秒数后失效。

 如果value是个datatime或timedelta,session就会在这个时间后失效。

 如果value是0,用户关闭浏览器session就会失效。

 如果value是None,session会依赖全局session失效策略。

3)session的相关配置

# settings.py
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)

4)Django中对应session的存储方式

Django中支持session,其中内部提供了5种类型的session供开发者使用:

  • 数据库(默认)
  • 缓存
  • 文件
  • 缓存+数据库
  • 加密cookie
1、如果是数据库,需要在settings.py中配置如下:

SESSION_ENGINE = 'django.contrib.sessions.backends.db' (引擎(默认))

2、如果是缓存session,需要在settings.py中配置如下:

SESSION_ENGINE = 'django.contrib.sessions.backends.cache'(引擎)

SESSION_CACHE_ALIAS= 'default'  使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

3、 如果是文件session, 需要在settings.py中配置如下:

SESSION_ENGINE = 'django.contrib.sessions.backends.file' (引擎)

SESSION_FILE_PATH=None  缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()   

4、如果是缓存+数据库session,需要在settings.py中配置如下:

SESSION_ENGINE='django.contrib.sessions.backends.cached_db'       (引擎)

3、利用django自带登录功能,实现自定义用户名或邮箱登录,及用户注册(邮箱激活)、忘记密码等功能

3.1 实现用户注册功能 

 

 3.1.1 验证码实现 --第三方库:Captcha

  1)安装captcha

pip install  django-simple-captcha

  2)在我们项目的setting.py中的INSTALLED_APPS注册captcha。需要注意的是,在INSTALLED_APPS中注册的,都需要经过makemigrations、migrate生成对应的表数据

INSTALLED_APPS = [
……
'captcha',
……
]

  3)配置urls.py

from django.urls import path,include,re_path

urlpatterns = [
# 验证码
re_path(r'^captcha', include('captcha.urls')),
]

通过上述几步,我们就能在项目中正常使用captcha了。用法很简单:

  1)后台用到验证码的地方:

from captcha.fields import CaptchaField

class RegisterForm(forms.Form):
"""注册表单验证""" captcha = CaptchaField(error_messages={'invalid':'验证码错误'})

  2)前端页面展示 --关于验证码:


<label>验&nbsp;证&nbsp;码</label>
{{ register_form.captcha }}

使用captcha实现验证码的好处:不需要我们判断前端验证码输入与原验证码是否一致(内部已实现了判断),只需要按上述几个步骤操作,即可实现注册/登录页面的验证码验证功能

 3.1.2 实现注册功能

  结合第三方库captcha,实现附有验证码的注册功能

  1)注册功能 --form表单验证

from django import forms
from django.core.exceptions import ValidationError from captcha.fields import CaptchaField class RegisterForm(forms.Form):
"""注册表单验证"""
email = forms.EmailField(required=True)
password = forms.CharField(required=True,min_length=6)
# 验证码 内部已经包含判断验证码是否正确,不需要进行下述的验证码验证代码编写
captcha = CaptchaField(error_messages={'invalid':'验证码错误'}) # 验证码验证,使用第三方库captcha时不需要再判断,属于画蛇添足
# def clean_captcha(self):
# print("captcha:",self.request.session.get('code'))
# print("valid_code:",self.cleaned_data.get('code'))
# if self.request.session.get('code').upper() == self.cleaned_data.get('code').upper():
# return self.cleaned_data['code']
# else:
# raise ValidationError('验证码不正确')
# 自定义方法(局部钩子),密码必须包含字母和数字
def clean_password(self):
if self.cleaned_data.get('password').isdigit() or self.cleaned_data.get('password').isalpha():
raise ValidationError('密码必须包含数字和字母')
else:
return self.cleaned_data['password'] # 自定义方法(全局钩子, 检验两个字段),可用于检验两次密码是否一致;
# def clean(self):
# if self.cleaned_data.get('password') != self.cleaned_data.get('password2'):
# raise ValidationError('密码不一致')
# else:
# return self.cleaned_data

forms.py

  2)views.py:

def register(request):
"""用户注册 """
if request.method == "POST":
register_form = forms.RegisterForm(request.POST)
if register_form.is_valid():
user_name = request.POST.get('email',None)
if UserProfile.objects.filter(email=user_name):
# 用户已经存在,不需要再注册
return render(request,'register.html',{'msg':'用户已经存在','register_form':register_form})
pass_word = request.POST.get('password', None)
# 将密码加密后再保存
pass_word = make_password(pass_word)
UserProfile.objects.create(
username=user_name,
email=user_name,
is_active=False,
password=pass_word
)
email_send_status = email_send.send_register_email(user_name, 'register') # 发送邮件,用于用户激活账号
if email_send_status: # 状态为1,表示邮件发送成功
email_send_success = True # 用于前端判断发送邮件的类型
return render(request,'send_email_success.html',locals())
else:
# status_form = True #用于前端注册时判断是否填充客户输入原数据
return render(request, 'register.html', {'msg':'用户名或密码格式错误','register_form':register_form}) else:
register_form = forms.RegisterForm()
return render(request,'register.html',locals())

  3)urls.py配置:

from django.urls import path
from web_online import views urlpatterns = [ path('register/',views.register, name='register'),
# 验证码url
re_path(r'^captcha',include('captcha.urls')), ]

  4)HTML前端代码(仅供参考):

<!DOCTYPE html>
{% load staticfiles %}
<html> <head>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
<title>慕学在线注册</title>
<link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'css/login.css' %}"> </head>
<body>
<div class="loginbox dialogbox">
<h1>账号登录</h1>
<div class="close jsCloseDialog"><img src="{% static 'images/dig_close.png' %}"/></div>
<div class="cont">
<form id="jsLoginForm" autocomplete="off">
<div class="box">
<span class="word3">用户名</span>
<input type="text" name="account_l" id="account_l" placeholder="手机号/邮箱" />
</div>
<div class="box">
<span class="word2">密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</span>
<input type="password" name="password_l" id="password_l" placeholder="请输入您的密码"/>
</div>
<div class="error btns login-form-tips" id="jsLoginTips"></div> <!--登录错误提示-->
<div class="btns">
<span><input type="checkbox" id="jsAutoLogin" />&nbsp;自动登录</span>
<span class="forget btn fr">忘记密码</span>
</div>
<div class="button">
<input type="button" value="登录" id="jsLoginBtn" />
</div>
<div class="btns">
<span class="fr">没有账号?<span class="regist btn">立即注册</span></span>
</div>
</form>
</div>
</div>
<div class="dialog" id="jsDialog">
<!--提示弹出框-->
<div class="successbox dialogbox" id="jsSuccessTips">
<h1>成功提交</h1>
<div class="close jsCloseDialog"><img src="{% static 'images/dig_close.png' %}"/></div>
<div class="cont">
<h2>您的需求提交成功!</h2>
<p></p>
</div>
</div>
<div class="noactivebox dialogbox" id="jsUnactiveForm" >
<h1>邮件验证提示</h1>
<div class="close jsCloseDialog"><img src="{% static 'images/dig_close.png' %}"/></div>
<div class="center">
<img src="{% static 'images/send.png' %}"/>
<p>我们已经向您的邮箱<span class="green" id="jsEmailToActive">12@13.com</span>发送了邮件,<br/>为保证您的账号安全,请及时验证邮箱</p>
<p class="a"><a class="btn" id="jsGoToEmail" target="_blank" href="http://mail.qq.com">去邮箱验证</a></p>
<p class="zy_success upmove"></p>
<p style="display: none;" class="sendE2">没收到,您可以查看您的垃圾邮件和被过滤邮件,也可以再次发送验证邮件(<span class="c5c">60s</span>)</p>
<p class="sendE">没收到,您可以查看您的垃圾邮件和被过滤邮件,<br/>也可以<span class="c5c green" id="jsSenEmailAgin" style="cursor: pointer;">再次发送验证邮件</span></p>
</div>
</div>
</div> <div class="bg" id="dialogBg"></div>
<header>
<div class="c-box fff-box">
<div class="wp header-box">
<p class="fl hd-tips">慕学在线,在线学习平台!</p>
<ul class="fr hd-bar">
<li>服务电话:<span>4001008031</span></li>
<li><a href="{% url 'login' %}">[登录]</a></li>
<li class="active"><a href="{% url 'register' %}">[注册]</a></li>
</ul>
</div>
</div>
</header>
<section>
<div class="c-box bg-box">
<div class="login-box clearfix">
<div class="hd-login clearfix">
<a class="index-logo" href="/index/"></a>
<h1>用户注册</h1>
<a class="index-font" href="/index/">回到首页</a>
</div>
<div class="fl slide">
<div class="imgslide">
<ul class="imgs"> <li><a href=""><img width="" height="" src="{% static 'images/57a801860001c34b12000460.jpg' %}" /></a></li> <li><a href=""><img width="" height="" src="{% static 'images/57a801860001c34b12000460.jpg' %}" /></a></li> <li><a href=""><img width="" height="" src="{% static 'images/57a801860001c34b12000460.jpg' %}" /></a></li> </ul>
</div>
<div class="unslider-arrow prev"></div>
<div class="unslider-arrow next"></div>
</div>
<div class="fl form-box">
<div class="tab">
<!--<h2 class="active">手机注册</h2>-->
<h2>邮箱注册</h2>
</div> <div class="tab-form">
<form id="email_register_form" method="post" action="{% url 'register' %}" autocomplete="off">
{% csrf_token %}
<div class="form-group marb20 {% if register_form.errors.email.0 %} errorput {% endif %}">
<label>邮&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;箱</label>
<input type="text" id="id_email" name="email" {% if register_form.email.value %} value="{{ register_form.email.value }}" {% endif %} placeholder="请输入您的邮箱地址" />
</div>
<div class="error btns" id="jsEmailTips">{{ register_form.errors.email.0 }}</div>
<div class="form-group marb8 {% if register_form.errors.password.0 %} errorput {% endif %}">
<label>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</label>
<input type="password" id="id_password" name="password" {% if register_form.password.value %} value="{{ register_form.password.value }}" {% endif %} placeholder="请输入6-20位非中文字符密码" />
</div>
<div class="error btns" id="jsEmailTips">{{ register_form.errors.password.0 }}</div>
<div class="form-group marb8 captcha1 {% if register_form.errors.captchal.0 %} errorput {% endif %}">
{# <label>验&nbsp;证&nbsp;码</label>#}
{# {{ register_form.captcha }}#}
<input name='code' type="text" placeholder="验证码" />
{{ register_form.captcha }}
</div>
<div class="error btns" id="jsEmailTips">{{ register_form.errors.captcha.0 }}</div>
<div class="error btns" id="jsEmailTips">
{{ msg }}
</div>
<div class="auto-box marb8">
</div>
<input class="btn btn-green" id="jsEmailRegBtn" type="submit" value="注册" /> </form>
</div>
<p class="form-p">已有账号?<a href="{% url 'login' %}">[立即登录]</a></p>
</div>
</div>
</div>
</section> <input id="isLogin" type="hidden" value="False"/>
<script src="{% static 'js/jquery.min.js' %}" type="text/javascript"></script>
<script src="{% static 'js/unslider.js' %}" type="text/javascript"></script>
<script src="{% static 'js/validateDialog.js' %}" type="text/javascript"></script>
<script src="{% static 'js/login.js' %}" type="text/javascript"></script>
</body>
</html>

register.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% if email_send_success %}
<p>【注册账号激活】邮件已发送,请移步邮箱中查收!</p>
{% else %}
<p>【密码重置】邮件已发送,请移步邮箱中查收!</p>
{% endif %} </body>
</html>

send_email_success.html

 3.1.3  注册账号激活 

  在上述注册功能实现过程中涉及到邮件激活账号:email_send.send_register_email(user_name,'register') , 下面实现注册账号激活功能

   注意:用户账号激活时,本质是通过is_active=True来实现的,如果将is_staff也设置为True,则表示该用户可以登录我们项目的django后台。切记,只有is_active、is_staff同时为True,才能登录django后台。

  1)email_send.py:用于给用户发送邮件,实现下述功能

  • 账号激活
  • 忘记密码,重置密码
  • 修改密码
import random
from users.models import EmailVerifyRecord
from django.core.mail import send_mail
from web_online import settings def random_str(random_length=16):
"""默认生成16位随机字符串"""
str = ''
# 生成字符串的可选字符串
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
length = len(chars) - 1
# ran_dom = random.Random()
for i in range(random_length):
str += chars[random.randint(0, length)]
return str # 发送邮件
def send_register_email(email, send_type="register"):
"""
发送邮件
发送前将当前注册用户保存到数据库,方便后台激活账号时能在数据库中找到对应的注册用户
"""
if send_type == 'update_email': # 修改密码操作
code = random_str(4) else:
code = random_str(16) # 保存到数据库
EmailVerifyRecord.objects.create(
code=code,
email=email,
send_type=send_type
) # 定义邮箱内容:
if send_type == "register": # 注册激活账号
subject = "Mx在线教育注册激活链接" # 标题
email_body = "请复制打开下面的链接激活你的账号:http://127.0.0.1:8000/active/{0}".format(code) # 文本邮件体
sender = settings.DEFAULT_FROM_EMAIL # 发件人
receiver = [email] # 接收人
email_send_status = send_mail(subject, email_body, sender, receiver)
return email_send_status
# if email_send_status:
# pass
elif send_type == 'forget': # 忘记密码 重置密码
subject = "Mx在线教育重置密码链接" # 标题
email_body = "请复制打开下面的链接重置密码:http://127.0.0.1:8000/reset/{0}".format(code) # 文本邮件体
sender = settings.DEFAULT_FROM_EMAIL # 发件人
receiver = [email] # 接收人
email_send_status = send_mail(subject, email_body, sender, receiver)
return email_send_status elif send_type == "update_email": # 修改密码验证码
subject = "Mx在线教育邮箱修改验证码"
email_body = "你的邮箱验证码为{0}".format(code)
sender = settings.DEFAULT_FROM_EMAIL
receiver = [email] # 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,从哪里发,接受者list
send_status = send_mail(subject, email_body, sender, receiver)
# 如果发送成功
if send_status:
pass

email_send.py

  2)使用django自带的邮件发送功能,需要在settings.py中配置发送邮件的基本数据:

# 邮箱配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = "smtp.163.com" #以163邮箱为例,SMTP服务器(邮箱需要开通SMTP服务)
EMAIL_HOST_PASSWORD = '******' #SMTP服务授权码
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER = "13*******@163.com" #我的163邮箱帐号
EMAIL_PORT = 25 #163邮箱SMTP服务端口
EMAIL_USE_TLS = True # 163、qq邮箱此值为True,aliyun此值为False,163可以忽略此值
# EMAIL_SUBJECT_PREFIX = '[yshblog.com]' #邮件标题前缀,默认是'[django]'

  3)views.py:

   注册账号激活功能

def user_active(request, accode):
"""注册用户账号激活"""
if request.method == "GET":
ac_records = EmailVerifyRecord.objects.filter(code=accode)
if ac_records: # 有当前注册用户
five_mintes_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
ac_record = ac_records[0]
# print("five_mintes_ago:",five_mintes_ago)
# print("send_time:",ac_record.send_time)
if five_mintes_ago > ac_record.send_time: # 发送时间超过5分钟,返回链接失效页面
return render(request, 'active_fail.html') ac_email = ac_record.email
ac_user = UserProfile.objects.get(email=ac_email) # 当前注册用户
ac_user.is_active = True
ac_user.save()
return render(request,'active_success.html',locals()) else:
return render(request,'active_fail.html')

  4)urls.py配置:

from django.urls import path
from web_online import views urlpatterns = [ re_path(r'^active/(\w+)/', views.user_active, name='user_active'), # 邮箱激活账号 ]

  5)注册成功返回页面、注册用户失败或链接失效返回页面:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>mx教育邮箱注册成功</title>
</head>
<body>
<h3>恭喜!您已成功激活账号:{{ ac_email }}</h3>
<p style="color: red">点击跳转:<a href="/login/">登录</a></p>
</body>
</html>

active_success.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p style="color: red;">链接已经失效</p>
</body>
</html>

active_fail.html

至此,用户注册及激活功能即完成。



3.2 实现自定义用户名或邮箱登录功能

  3.2.1 userProfile继承于 AbstractUser

    需要注意的是:AbstractUser中定义的email字段不具有唯一性,容易造成多个用户使用同一邮箱,当使用邮箱登录时会造成冲突。因此,需要重写email字段,使其与username字段一样,具备 '唯一'性

from django.db import models
from django.contrib.auth.models import AbstractUser class UserProfile(AbstractUser):
"""用户"""
gender_choices = (
('male','男'),
('female','女')
) nick_name = models.CharField('昵称',max_length=32 ,default='')
birthday = models.DateField('生日',null=True,blank=True)
gender = models.CharField('性别',max_length=8,choices=gender_choices,default='female')
adress = models.CharField('地址',max_length=100,default='')
mobile = models.CharField('手机号',max_length=11,null=True,blank=True)
image = models.ImageField(upload_to='image/%Y/%m',default='image/default.png',max_length=100)
email = models.EmailField('邮箱', blank=True,unique=True) # 重写email字段,加上'唯一'标识 class Meta:
verbose_name = '用户信息'
verbose_name_plural = verbose_name def __str__(self):
return self.username

此时 userProfile表所存字段:

 

 3.2.2 在views中编写登录功能之前,我们需要先写一个form表单,用于用户登录时,对用户名及密码格式进行验证:

     forms.py/LoginForm

from django import forms

class LoginForm(forms.Form):
"""登录表单验证"""
username = forms.CharField(required=True)
password = forms.CharField(required=True, min_length=6)

 3.2.3 接着在views界面中编写我们的登录代码:

from django.shortcuts import render,redirect
from django.contrib.auth import authenticate ,login ,logout
from users.models import UserProfile
from web_online import forms def mx_login(request):
"""登录"""
login_form = forms.LoginForm()
if request.method == "POST":
login_form = forms.LoginForm(request.POST)
if login_form.is_valid():
user_name = request.POST.get('username',None)
pass_word = request.POST.get('password',None)
user = authenticate(username=user_name, password=pass_word)
if user:
if user.is_active:
# 只有注册激活才能登陆
login(request,user)
return redirect('/index/')
else:
return render(request,'login.html',{'msg': '用户未激活', 'login_form': login_form})
else:
return render(request, 'login.html', {'msg': '用户名或密码错误', 'login_form': login_form})
else:
return render(request, 'login.html', {'msg': '用户名或密码格式错误,请重新输入!', 'login_form': login_form}) return render(request,"login.html")

简单解析:

 1. is_active:在注册中,我们对成功激活账号的用户设置is_active为True,在登录操作中就可以通过is_active的状态来判断用户是否是注册成功的用户,来决定是否给用户登录权限

 2. authenticate()方法的验证:我们使用的是django自带的authenticate验证, 默认只对用户名、密码进行验证,我们要使用用户名或邮箱进行验证,需要自定义authenticate方法,实现代码如下:

class CustomBackend(ModelBackend):
"""
用于mx_login用户登录验证
需在settings中配置好authenticate验证方式(即在此进行authenticate的相关验证)
"""
def authenticate(self, request, username=None, password=None, **kwargs):
# 重写authenticate方法
try:
user = UserProfile.objects.get(Q(username=username)|Q(email=username))
if user.check_password(password):
"""
1.在注册时,我们对密码使用了加密处理(django下的make_password),因此在登录验证密码时需要先将明文密码加密
后才能跟数据库中已加密后的密码进行比较
2.check_password()是AbstractUser类中的方法,UserProfile继承于AbstractUser,check_password会加密明文密
码后,与数据库密码做对比,再进行判断两密码是否一致
3.验证如果为True,表示密码一致;为False,表示密码不一致
"""
return user
else:
return None except Exception as e:
return None

 以上基本实现了自定义登录功能验证,但要验证流程中的authenticate验证走我们自定义的authenticate验证,需要在settings.py中配置AUTHENTICATION_BACKENDS ,如不配置,默认会走django自带的authenticate验证:

AUTHENTICATION_BACKENDS = ( # 登录认证设置
'web_online.views.CustomBackend', #CustomBackend所在路径
)

 3.2.4 url配置:

from django.urls import path
from web_online import views urlpatterns = [ path('login/',views.mx_login, name='login'), ]

 3.2.5 html配置:

   注意:HTML前端代码未附带css、js代码,仅供参考

<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
<title>慕学在线网登录</title>
<link rel="stylesheet" type="text/css" href="/static/css/reset.css">
<link rel="stylesheet" type="text/css" href="/static/css/login.css">
</head>
<body>
<div class="dialog" id="jsDialog">
<!--提示弹出框,用于找回密码操作时的提示-->
<div class="successbox dialogbox" id="jsSuccessTips">
<h1>成功提交</h1>
<div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
<div class="cont">
<h2>您的需求提交成功!</h2>
<p></p>
</div>
</div>
<div class="noactivebox dialogbox" id="jsUnactiveForm" >
<h1>邮件验证提示</h1>
<div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
<div class="center">
<img src="/static/images/send.png"/>
<p>我们已经向您的邮箱<span class="green" id="jsEmailToActive">12@13.com</span>发送了邮件,<br/>为保证您的账号安全,请及时验证邮箱</p>
<p class="a"><a class="btn" id="jsGoToEmail" target="_blank" href="http://mail.qq.com">去邮箱验证</a></p>
<p class="zy_success upmove"></p>
<p style="display: none;" class="sendE2">没收到,您可以查看您的垃圾邮件和被过滤邮件,也可以再次发送验证邮件(<span class="c5c">60s</span>)</p>
<p class="sendE">没收到,您可以查看您的垃圾邮件和被过滤邮件,<br/>也可以<span class="c5c green" id="jsSenEmailAgin" style="cursor: pointer;">再次发送验证邮件</span></p>
</div>
</div>
</div>
<div class="bg" id="dialogBg"></div>
<header>
<div class="c-box fff-box">
<div class="wp header-box">
<p class="fl hd-tips">慕学在线网,在线学习平台!</p>
<ul class="fr hd-bar">
<li>服务电话:<span>33333333</span></li>
<li class="active"><a href="{% url 'login' %}">[登录]</a></li>
<li><a href="{% url 'register' %}">[注册]</a></li>
</ul>
</div>
</div>
</header>
<section>
<div class="c-box bg-box">
<div class="login-box clearfix">
<div class="hd-login clearfix">
<a class="index-logo" href="/index/"></a>
<h1>用户登录</h1>
<a class="index-font" href="/index/">回到首页</a>
</div>
<div class="fl slide">
<div class="imgslide">
<ul class="imgs">
<li><a href=""><img width="" height="" src="/static/images/mysql.jpg"/></a></li>
<li><a href=""><img width="" height="" src="/static/images/mysql.jpg"/></a></li>
<li><a href=""><img width="" height="" src="/static/images/mysql.jpg"/></a></li>
</ul>
</div>
<div class="unslider-arrow prev"></div>
<div class="unslider-arrow next"></div>
</div>
<div class="fl form-box">
<h2>帐号登录</h2>
<form action="/login/" method="post" autocomplete="off">
{% csrf_token %}
<div class="form-group marb20 {% if login_form.errors.username.0 %} errorput {% endif %}">
<label>用&nbsp;户&nbsp;名</label>
<input name="username" id="account_l" type="text" placeholder="手机号/邮箱" {% if login_form.username.value %}value="{{ login_form.username.value }}"{% endif %}/>
</div>
<div class="error btns login-form-tips" id="jsLoginTips">{{ login_form.errors.username.0 }}</div>
<div class="form-group marb8 {% if login_form.errors.password.0 %} errorput {% endif %}">
<label>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</label>
<input name="password" id="password_l" type="password" {% if login_form.password.value %}value="{{ login_form.password.value }}"{% endif %} placeholder="请输入您的密码"/>
</div>
<div class="error btns login-form-tips" id="jsLoginTips">{{ login_form.errors.password.0 }}</div>
<div class="error btns login-form-tips" id="jsLoginTips">{{ msg }}</div>
<div class="auto-box marb38"> <a class="fr" href="#">忘记密码?</a>
{# <a class="fr" href="{% url 'forgetpwd' %}">忘记密码?</a>#}
</div>
<input class="btn btn-green" id="jsLoginBtn" type="submit" value="立即登录 > "/>
<input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy'/>
{% csrf_token %}
</form>
<p class="form-p">没有慕学在线网帐号?<a href="{% url 'register' %}">[立即注册]</a></p>
</div>
</div>
</div>
</section>
<script src="/static/js/jquery.min.js" type="text/javascript"></script>
<script src="/static/js/unslider.js" type="text/javascript"></script>
<script src="/static/js/login.js" type="text/javascript"></script>
</body>
</html>

login.html



 3.3 退出登录功能

   3.3.1 退出登录

     实现退出登录功能很简单,在views.py中编写退出登录代码:

from django.contrib.auth import logout

def mx_logout(request):
"""退出登录"""
logout(request)
return redirect('/login/') # 返回登录页面

    3.3.2 url配置:

from django.urls import path
from web_online import views urlpatterns = [ path('logout/',views.mx_logout, name='logout'), ]

注:退出登录功能,没有HTML前端代码



3.4 实现忘记密码、找回密码功能

 点击 [忘记密码],进入找回密码,根据注册邮箱,找回密码

      

 3.4.1 根据注册用户邮箱,发送验证邮件

  1)views.py:

def forget_pwd(request):
"""忘记密码,通过邮箱找回密码"""
message = {}
if request.method == "POST":
forget_pwd_form = forms.ForgetPwdForm(request.POST)
if forget_pwd_form.is_valid():
email = request.POST.get('email',None)
user_objs = UserProfile.objects.filter(email=email)
if user_objs: # 判断邮箱是否存在
send_status = email_send.send_register_email(email,'forget')
if send_status: # 邮件发送成功
email_send_success = False # 用于前端判断发送邮件的类型
return render(request,'send_email_success.html',locals())
else:
message['msg'] = '该邮箱不存在'
message['status'] = True
return render(request, 'forgetpwd.html', {'message': message, 'forget_pwd_form': forget_pwd_form})
else: # form表单验证不通过
message['msg'] = '邮箱或验证码错误'
message['status'] = True
return render(request,'forgetpwd.html',{'message':message,'forget_pwd_form' : forget_pwd_form})
else:
forget_pwd_form = forms.ForgetPwdForm()
return render(request,'forgetpwd.html',{'forget_pwd_form' : forget_pwd_form})

  2)forms.py 表单验证:

class ForgetPwdForm(forms.Form):
"""忘记密码"""
email = forms.EmailField(required=True)
captcha = CaptchaField(error_messages={'invalid': '验证码错误'})

  3)urls.py:

from django.urls import path
from web_online import views urlpatterns = [ path('forgetpwd/', views.forget_pwd, name='forgetpwd'), # 忘记密码 ]

  4)HTML前端代码:

<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<title>慕学网首页</title>
<link rel="stylesheet" type="text/css" href="/static/css/reset.css">
<link rel="stylesheet" type="text/css" href="/static/css/login.css">
</head>
<body>
<!--提示弹出框-->
<div class="successbox dialogbox" id="jsSuccessTips">
<h1>成功提交</h1>
<div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
<div class="cont">
<h2>您的需求提交成功!</h2>
<p></p>
</div>
</div>
<div class="resetpassbox dialogbox" id="jsSetNewPwd">
<h1>重新设置密码</h1>
<div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
<p class="green">请输入新密码</p>
<form id="jsSetNewPwdForm">
<div class="box">
<span class="word2">密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</span>
<input type="password" name="password" id="jsResetPwd" placeholder="请输入新密码"/>
</div>
<div class="box">
<span class="word2">确&nbsp;认&nbsp;密&nbsp;码</span>
<input type="password" name="password2" id="jsResetPwd2" placeholder="请再次输入新密码"/>
</div>
<div class="box">
<span class="word2">验&nbsp;&nbsp;证&nbsp;&nbsp;码</span>
<input type="text" name="code" id="jsResetCode" placeholder="请输入手机验证码"/>
</div>
<div class="error btns" id="jsSetNewPwdTips"></div>
<div class="button">
<input type="hidden" name="mobile" id="jsInpResetMobil"/>
<input id="jsSetNewPwdBtn" type="button" value="提交"/>
</div>
</form>
</div>
<div class="bg" id="dialogBg"></div>
<header>
<div class="c-box fff-box">
<div class="wp header-box">
<p class="fl hd-tips">慕学网,在线学习平台!</p>
<ul class="fr hd-bar">
<li>服务电话:<span>33333333</span></li>
<li><a href="{% url 'login' %}">[登录]</a></li>
<li class="active"><a href="/forgetpwd/">[忘记密码]</a></li>
</ul>
</div>
</div>
</header>
<section>
<div class="c-box bg-box">
<div class="login-box clearfix">
<div class="hd-login clearfix">
<a class="index-logo" href="{% url 'index' %}"></a>
<h1>忘记密码</h1>
<a class="index-font" href="{% url 'index' %}">回到首页</a>
</div>
<div class="fl slide">
<div class="imgslide">
<ul class="imgs">
<li><a href=""><img width="" height="" src="/static/images/57a801860001c34b12000460.jpg"/></a>
</li>
<li><a href=""><img width="" height="" src="/static/images/57a801860001c34b12000460.jpg"/></a>
</li>
<li><a href=""><img width="" height="" src="/static/images/57a801860001c34b12000460.jpg"/></a>
</li>
</ul>
</div>
<div class="unslider-arrow prev"></div>
<div class="unslider-arrow next"></div>
</div>
<div class="fl form-box">
<h2>忘记密码</h2>
<form id="jsFindPwdForm" method="post" autocomplete="off">
{% csrf_token %}
<div class="form-group marb20 {% if forget_pwd_form.errors.email.0 %} errorput {% endif %}">
<label>帐&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;号</label>
<input type="text" id="account" name="email" {% if message.status %} value="{{ forget_pwd_form.email.value }}" {% endif %} placeholder="请输入邮箱号"/>
</div>
<div class="form-group captcha1 marb38 {% if forget_pwd_form.errors.captchal.0 %} errorput {% endif %}">
<label>验&nbsp;证&nbsp;码</label>
{{ forget_pwd_form.captcha }}
</div>
<div class="error btns" id="jsForgetTips">{{ message.msg }}</div>
<input type="hidden" name="sms_type" value="">
<input class="btn btn-green" id="jsFindPwdBtn" type="submit" value="提交"/>
<p class="form-p" style="bottom:40px;">您还可以<a href="{% url 'login' %}"> [直接登录]</a></p>
</form>
</div>
</div>
</div>
</section> <input id="isLogin" type="hidden" value="False"/>
<script src="/static/js/jquery.min.js" type="text/javascript"></script>
<script src="/static/js/unslider.js" type="text/javascript"></script>
<script src="/static/js/validateDialog.js" type="text/javascript"></script>
<script src="/static/js/login.js" type="text/javascript"></script>
</body>
</html>

forgetpwd.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% if email_send_success %}
<p>【注册账号激活】邮件已发送,请移步邮箱:{{ user_name }} 中查收!</p>
{% else %}
<p>【密码重置】邮件已发送,请移步邮箱:{{ email }} 中查收!</p>
{% endif %} </body>
</html>

send_email_success.html

  5)email_send

   【密码重置】发送邮件的相关代码与用户注册账号激活整合在一起,详见用户注册账号激活 --发送邮件


 3.4.2 重置密码

  1)forms.py:

class ModifyPwdForm(forms.Form):
"""重置密码"""
password1 = forms.CharField(required=True, min_length=6)
password2 = forms.CharField(required=True, min_length=6) def clean_password1(self):
if self.cleaned_data.get('password1').isdigit() or self.cleaned_data.get('password1').isalpha():
raise ValidationError('密码必须包含数字和字母')
else:
return self.cleaned_data['password1']

  2)views.py:

# 确定当前用户邮箱是否正确,如正确转到重置密码页面,进行密码重置

def pwd_reset(request,ac_code):
"""用户重置密码链接"""
if request.method =="GET":
records = EmailVerifyRecord.objects.filter(code=ac_code)
if records:
email = records[0].email
return render(request, "password_reset.html", {"email": email})
else:# 链接不对
return render(request, "active_fail.html")
# 重置密码

def modify_pwd(request):
"""重置密码"""
if request.method == "POST":
modify_form = forms.ModifyPwdForm(request.POST)
if modify_form.is_valid():
pwd1 = request.POST.get("password1", None)
pwd2 = request.POST.get("password2", None)
# email数据是从pwd_reset获取到的
email = request.POST.get("email", None)
if pwd1 != pwd2:
return render(request, "password_reset.html", {"email": email, "msg": "密码不一致!"})
user = UserProfile.objects.get(email=email)
user.password = make_password(pwd2)
user.save()
return render(request, "login.html")
else:
email = request.POST.get("email", None)
return render(request, "password_reset.html", {"email": email, "modify_form": modify_form})
else:
return render(request, 'password_reset.html')

  3)urls.py配置

from django.urls import path
from web_online import views urlpatterns = [ re_path(r'^reset/(\w+)/',views.pwd_reset,name='reset'), # 邮箱重置密码链接
path('modify_pwd/',views.modify_pwd,name='modify_pwd'), # 重置密码 ]

  4)HTML前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<title>密码修改</title>
<link rel="stylesheet" type="text/css" href="/static/css/reset.css">
<link rel="stylesheet" type="text/css" href="/static/css/animate.css">
<link rel="stylesheet" type="text/css" href="/static/css/style.css"> <body>
<div class="wp">
<div class="resetpassword" id="resetPwdForm">
<h1>修改密码</h1>
<p>已经通过验证,请设置新密码</p>
<form id="reset_password_form" action="{% url 'modify_pwd' %}" method="post">
{% csrf_token %}
<ul>
<li class="{% if modify_form.errors.password1.0 %} errorput {% endif %}">
<span class="">新 密 码 :</span>
<input type="password" name="password1" id="pwd" placeholder="6-20位非中文字符">
<i></i>
</li>
<input type="hidden" name="email" value="{{ email }}">
<li class="{% if modify_form.errors.password2.0 %} errorput {% endif %}">
<span class="">再次输入密码 :</span>
<input type="password" name="password2" id="repwd" placeholder="6-20位非中文字符">
<i></i>
</li>
<div class="error btns" id="jsPasswdResetTips" style="color: red">
{% for key,error in modify_form.errors.items %}{{ key }}:{{ error }}{% endfor %}
{{ msg }}
</div>
<li class="button">
<input type="submit" value="提交">
</li>
</ul>
</form>
</div>
<div class="resetpassword" id="reset_password_tips" style="display:none;">
<h1>修改密码成功,请重新登录</h1>
<img class="fl" src="/static/images/check2.png">
<p class="successword">已经成功修改密码,请重新登录</p>
</div>
</div>
</body>
</html>

password_reset.html



未完待续。。

python相关注册登录方式的更多相关文章

  1. python实现注册登录小程序

    用python 实现模拟注册和登录的程序:用户信息最终以字典的格式储存在一个txt文件里,具体实现如下: users.txt里用户字典格式如下: { '}, '}, '} } # 注册 f = ope ...

  2. 如何设计一个 App 的注册登录流程?

    移 动设备发力之前的登录方式很简单:用户名/邮箱+密码+确认密码,所有的用户登录注册都是围绕着邮箱来做.随着移动设备和社交网络的普及,邮箱不再是唯 一,渐渐的出现了微博,QQ,微信等第三方登录方式,手 ...

  3. Python简单的登录注册代码

    #-*- coding: utf-8 -*- import hashlib # 定义数据库(声明字典) #注册登录的简单hash处理 db={} def get_md5(password): md5= ...

  4. 【Python五篇慢慢弹(5)】类的继承案例解析,python相关知识延伸

    类的继承案例解析,python相关知识延伸 作者:白宁超 2016年10月10日22:36:57 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给 ...

  5. 一步步开发自己的博客 .NET版(3、注册登录功能)

    前言 这次开发的博客主要功能或特点:    第一:可以兼容各终端,特别是手机端.    第二:到时会用到大量html5,炫啊.    第三:导入博客园的精华文章,并做分类.(不要封我)    第四:做 ...

  6. 手机app开发:浅谈APP登录方式的优劣

    手机app开发公司亿合科技要是给你一个机会设计一款APP,你会用什么方式做这个APP的登录模块?根据APP的业务模型的不同会有不同的设计方法.如果是偏内容型的APP,需要优先展示内容给用户,当用户需要 ...

  7. 用python实现模拟登录人人网

    用python实现模拟登录人人网 字数4068 阅读1762 评论19 喜欢46 我决定从头说起.懂的人可以快速略过前面理论看最后几张图. web基础知识 从OSI参考模型(从低到高:物理层,数据链路 ...

  8. express+vue+mongodb+session 实现注册登录

    上个月写了一篇文章是 express+mongodb+vue 实现增删改查. 只是简单的实现了增删改查功能,那么今天是在那个基础之上做了扩展,首先实现的功能有如下: 1. 支持注册,登录功能,用户可以 ...

  9. Spring Security构建Rest服务-1202-Spring Security OAuth开发APP认证框架之重构3种登录方式

    SpringSecurityOAuth核心源码解析 蓝色表示接口,绿色表示类 1,TokenEndpoint 整个入口点,相当于一个controller,不同的授权模式获取token的地址都是 /oa ...

随机推荐

  1. [UE4]修改瞬移操作方式,默认正前方

    瞬移的时候,如果箭头指向正前方的角度跟中心线相差不大,则可以强制箭头指向中心线. 因为向量也可以表示方向,因此只要只要判断向量长度就是了,判断VectorLength值即可:

  2. [UE4]瞬移前后屏幕亮度变化,Get Player Camera Manager.Start Camera Fade

    From Alpha:开始的颜色透明度 To Alpha:结束的颜色透明度 Duration:过渡所使用的时间(单位:秒) Color:屏幕变化的颜色 Hold when finished:过渡时间结 ...

  3. 网页中HTML代码如何实现字体删除线效果

    有的朋友在制作网站的时候,需要给字体制作删除线,例如:选择题,错误标识等!那么我们就需要用到了<s>这个标签写法如下 字体删除线: <s>这里是内容</s> 效果如 ...

  4. docker环境安装与开启远程访问

    一,安装docker 1,服务器安装 docker yum install docker 直接yum安装版本太低 2,卸载:老版本的Docker在yum中名称为docker或docker-engine ...

  5. LeetCode 789. Escape The Ghosts

    题目链接:https://leetcode.com/problems/escape-the-ghosts/description/ You are playing a simplified Pacma ...

  6. com.android.build.api.transformException报错的解决方法

    最近遇到一个问题:工程需要依赖模块1和模块2,但是模块1和模块2都使用了opencv,但opencv的版本不同,如果同时依赖两个模块,就会报错重复定义...如果模块2依赖模块1,工程再依赖模块2,也会 ...

  7. js 连接mqtt

    js连接mqtt 项目中要用到mqtt,前端调用,使用github开源的paho-mqtt.js,api还是挺全面的,网上各种教程很全面,但是感觉代码过于杂乱,故而封装的一下.仿jquery ajax ...

  8. Error occurred during initialization of VM Could not reserve enough space for object heap

    Error occurred during initialization of VM Could not reserve enough space for object heap Java虚拟机(JV ...

  9. 对Spring Ioc的理解

    1. 新建一个maven项目,工程目录如下 2. 添加接口MessageService及其实现类MessageServiceImpl MessageService.java package com.p ...

  10. Android开发 解决EditText与NestedScrollView 滚动冲突问题

    问题简述 在将EditText套进NestedScrollView的情况下,EditText输入了多行内容后,无法触摸滚动到第一行 问题原因 在将EditText套进NestedScrollView的 ...