Django建教育平台(七)--用户登录
来源:互联网 发布:田宫四驱车淘宝店 编辑:程序博客网 时间:2024/04/26 11:14
上一节说明的index和login页面, 并不需要专门写views, 因为是使用系统自带的templateview
这一节说明用户登录功能, 因为不是使用系统自带的view, 需要自己写login信息输入后的view.
1. 写用户登录view
a. 写粗略的users/views
from django.shortcuts import renderdef user_login(request): if request.method == "POST": pass elif request.method == "GET": return render(request, "login.html", {})
b. 修改urls文件
from users.views import user_login # 新增代码urlpatterns = [ url(r'^xadmin/', xadmin.site.urls), url('^$', TemplateView.as_view(template_name="index.html"), name="index"), url('^login/$', user_login, name="login") # 将原来的login写法修改成这样]
c. 在views中打断点
注意图中def login改成def user_login
d. Run菜单中按Debug
e. 浏览器访问http://127.0.0.1:8000/login/
f. 观察pycharm中断点情况
标蓝色的那一行即是现在运行所在行, 进入了GET的判断分支, 在下方debug窗口可以看到request是WSGIRequest对象.
点击debug窗口中request变量左侧的三角形, 展开request, 可以看到method和path这两者内容:
按F8将剩余代码运行完毕, 然后查看浏览器效果, 已经正常显示login页面.
g. 修改login.html中form action
在login.html中搜索"帐号登录"
修改标红色线处:
修改后:
h. 浏览器确认效果
点击立即登录按钮, 出现CSRF报错
在login.html中增加csrf_token
在浏览器中查看csrf_token的机制, 就是通过跟服务器确认一个随机生成的密钥, 防止恶意post给服务器.
第一步, 进入开发者工具模式.
第二步, 点击①所指的按钮
第三步, 点击②所指的"立即登录"
第四步, 查看③所指的位置, 就能看到django隐藏input的密钥
i. 验证用户身份, 登录
在users/views中设置断点
然后在浏览器输入之前注册的用户和密码, 按"立即登录".
pycharm中views断点标蓝色了.
在debug窗口中看到request变量, 展开该变量, 能找到里边的POST QueryDict.
展开POST QueryDict, 能看到里边的username, password键值信息, 跟我们刚在浏览器输入的是一样的.
现在就知道该如何取出POST中的内容了.
修改users/views代码
from django.shortcuts import renderfrom django.contrib.auth import authenticate, login # 新增代码def user_login(request): if request.method == "POST": user_name = request.POST.get("username", "") # 新增, 根据刚才断点的分析结果, 用字典方法取出username的值 pass_word = request.POST.get("password", "") # 新增, 根据刚才断点的分析结果, 用字典方法取出password的值 user = authenticate(username=user_name, password=pass_word) # 新增, 利用django自带的authenticate方法来确认这个用户是否合法, 如果合法, 则user是一个非空对象. if user is not None: # 如果该用户合法, 则user非空. login(request, user) # django自带的login方法 return render(request, "index.html") # 登录成功后返回首页 elif request.method == "GET": return render(request, "login.html", {})
2. 登录状态的判断
没有登录跟登录之后, 首页的显示状态不同.
未登录是这个样子的, 提示用户登录或者注册.
登陆后, 应该是这样子的, 点击后还能弹出进入个人中心或者退出的按钮.
要实现这样的显示差异, 需要判断是否登录,并作出相应改变.
a. 在index.html中修改以下代码:
<section class="headerwrap "> <header><div class=" header"> <div class="top"><div class="wp"><div class="fl"><p>服务电话:<b>33333333</b></p></div><!--登录后跳转-->{% if request.user.is_authenticated %} <!判断用户是否通过认证> <div class="personal"> <dl class="user fr"> <dd>bobby<img class="down fr" src="/static/images/top_down.png"/></dd> <dt><img width="20" height="20" src="/static/media/image/2016/12/default_big_14.png"/></dt> </dl> <div class="userdetail"> <dl> <dt><img width="80" height="80" src="/static/media/image/2016/12/default_big_14.png"/></dt> <dd> <h2>django</h2> <p>bobby</p> </dd> </dl> <div class="btn"> <a class="personcenter fl" href="usercenter-info.html">进入个人中心</a> <a class="fr" href="/logout/">退出</a> </div> </div> </div> {% else %} <!若用户未通过认证, 则显示以下按钮> <a style="color:white" class="fr registerbtn" href="register.html">注册</a> <a style="color:white" class="fr loginbtn" href="login.html">登录</a> {% endif %}</div></div> <div class="middle">
在login页面输入已注册的用户名和密码, 按立即登录, 跳转到index页面, index页面中已按照我们的设想显示.
b.非登录状态的验证
但是现在我们网站一直处于登录状态, 为了检查非登陆状态的页面, 我们先进入http://127.0.0.1:8000/xadmin/页面, 把当前用户注销, 然后再访问主页, 得到以下页面.
3. 设置邮箱登录
目前登录只能用用户名登录, 不能用邮箱登录.
在users/views中添加以下代码:
from django.contrib.auth.backends import ModelBackendfrom django.db.models import Q # Q可以帮助实现并集from .models import UserProfileclass CustomBackend(ModelBackend): def authenticate(self, username=None, password=None, **kwargs): try: user = UserProfile.objects.get(Q(username=username) | Q(email=username)) # 会用username或者email对传入的username进行匹配 if user.check_password(password): return user except Exception as e: return None
在settings中增加以下代码:
在installed_apps前面增加代码
AUTHENTICATION_BACKENDS = ( 'users.views.CustomBackend', # 逗号不要省)
然后尝试用邮箱登录, 成功了.
4. 设置登录错误提示
当输入登录帐号或密码错误时, 应该给出提示
a. 在users/views中修改代码:
def user_login(request): if request.method == "POST": user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") user = authenticate(username=user_name, password=pass_word) if user is not None: login(request, user) return render(request, "index.html") else: return render(request, "login.html", {"msg": "用户名或密码错误!"}) # 新增 msg 错误提示信息 elif request.method == "GET": return render(request, "login.html", {})
b. 将msg信息传给login.html
在login.html中以下位置插入{{ msg }}
故意输入错误的用户名或密码, 按登录后出现了提示信息.
5. 用class重写login的view
a. 将users/views中user_login函数注释掉
# def user_login(request):# if request.method == "POST":# user_name = request.POST.get("username", "")# pass_word = request.POST.get("password", "")# user = authenticate(username=user_name, password=pass_word)# if user is not None:# login(request, user)# return render(request, "index.html")# else:# return render(request, "login.html", {"msg": "用户名或密码错误!"})# elif request.method == "GET":# return render(request, "login.html", {})
from django.views.generic.base import View # import Viewclass LoginView(View): def get(self, request): # 重写View的GET方法 return render(request, "login.html", {}) # 将user_login函数的GET判断分支的代码拉过来. def post(self, request): # 重写View的POST方法 user_name = request.POST.get("username", "") # 将user_login函数的POST判断分支的代码拉过来. pass_word = request.POST.get("password", "") user = authenticate(username=user_name, password=pass_word) if user is not None: login(request, user) return render(request, "index.html") else: return render(request, "login.html", {"msg": "用户名或密码错误!"})
经过测试, LoginView类是可以正常实现之前user_login函数的功能的
c. 配置主页的登录链接
由于index.html中设置login页面的链接方式有两种, 一种是/login/, 一种是login.html, 目前url指匹配第一种.
urlpatterns = [ url(r'^xadmin/', xadmin.site.urls), url('^$|^index.html$', TemplateView.as_view(template_name="index.html"), name="index"), # 正则表达式表示A,B两模式匹配其中之一的, 写成A|B url('^login/$|login.html$', LoginView.as_view(), name="login"), # 正则表达式表示A,B两模式匹配其中之一的, 写成A|B]
当用户登录时输入一些不合法信息时, 希望能提前检出不合法性, 减少服务器访问负担, 并提醒用户正确输入.
a. 在users下新建forms.py文件, 输入代码
__author__ = 'Elvan'__date__ = '2017/8/13 19:39'from django import formsclass LoginForm(forms.Form): username = forms.CharField(required=True) # 将username设置为必填字段 password = forms.CharField(required=True, min_length=5) # 将password设置为必填字段, 且最短长度是5
b. users/views中修改代码
from .forms import LoginForm# 中间代码省略class LoginView(View): def get(self, request): return render(request, "login.html", {}) def post(self, request): login_form = LoginForm(request.POST) # 实例化LoginForm类的对象, 需传入request.POST参数 if login_form.is_valid(): # 检查login_form是否出错, 没出错的才验证用户名和密码 user_name = request.POST.get("username", "") pass_word = request.POST.get("password", "") user = authenticate(username=user_name, password=pass_word) if user is not None: login(request, user) return render(request, "index.html") else: return render(request, "login.html", {"msg": "用户名或密码错误!"}) else: return render(request, "login.html", {"login_form":login_form}) # 如果login_form出错, 则返回login_from对象, 在前端进一步处理
c. 提取login_form中error信息
在if login_form is_valid(): 这句前打断点
在login页面故意不输入任何信息即点击登录
到断点位置, 按F6 step over, 查看debugger窗口, 把login_form对象展开, 把_errors这个Dict展开, 看到password和username信息.
d. 将error信息传递到login.html
红色边框提示
修改前:
<div class="form-group marb20 "><label>用 户 名</label><input name="username" id="account_l" type="text" placeholder="手机号/邮箱" /></div><div class="form-group marb8 "><label>密 码</label><input name="password" id="password_l" type="password" placeholder="请输入您的密码" /></div>
修改后:
<div class="form-group marb20 {% if login_form.errors.username %}errorput{% endif %}"><label>用 户 名</label><input name="username" id="account_l" type="text" placeholder="手机号/邮箱" /></div><div class="form-group marb8 {% if login_form.errors.password %}errorput{% endif %}"><label>密 码</label><input name="password" id="password_l" type="password" placeholder="请输入您的密码" /></div>
在浏览器查看效果:
当不输入用户名或密码时, 改输入框会变红色边框.
错误语言提示:
修改前:
<div class="error btns login-form-tips" id="jsLoginTips">{{ msg }}</div>
修改后:
<div class="error btns login-form-tips" id="jsLoginTips">{% for key, error in login_form.errors.items %}{{ error }}{% endfor %}{{ msg }}</div>
浏览器查看效果, 在不输入用户名和密码的时候, 点击登录.
7. session和cookie自动登录机制
为什么需要cookie? 因为http协议本身是一种无状态的协议, 客户端对服务器的每一次请求都是独立的, 请求之间没有联系. 各个客户端对服务器来说都是一样的, 服务器不认客户端.
为了让服务器区别对待不同的客户端, 认客户端, 服务器给客户端发"会员卡".
下图解读,
客户端A第一次给服务器发请求1;
服务器收到请求1, 发现客户端A是首次来访, 然后就给A发会员卡, 会员卡ID=1.
客户端A收到会员卡后就储存着, 当第二次给服务器发送请求2时, 带上会员卡.
服务器收到请求2, 发现会员卡时, 就给客户端A发送相对应的"会员服务套餐".
浏览器访问百度, 进入开发者工具模式
能看到Cookies是由Name和Value组成的, 类似字典.
同样, 访问本地网站主页时, 也能看到cookies
将用户名和密码在客户端与服务器之间传来传去是危险的, 因此, 服务器会根据客户端传来的cookies, 生成一个session id, 客户端和服务器传递这个session id就可以了.
cookies和session都是储存在本地的(session也存在服务器端), session就存在django数据库中.
在用户已登录的状态下,查看django_session表.
打开表格, 是可以看到session信息的.
用户名, 密码等信息经过加密, 以字符串的形式储存在session_data键中, 在过期时间之前访问.
expire_date即过期时间, 是可以在django中设定过多长时间失效.
注意, 第二条session_key跟浏览器中cookies信息是一致的.
- Django建教育平台(七)--用户登录
- Django建教育平台(八)--用户注册
- Django建教育平台(六)--首页和登录页面配置
- Django建教育平台(二)--Users App
- Django建教育平台(四)--Django Admin与Xadmin
- Django建教育平台(一)--搭建环境,新建项目
- Django建教育平台(三)--创建各App及其model
- Django建教育平台(五)--各app的model注册
- Django实现用户登录
- django 用户登录及验证
- Django(七)----Django的用户认证,form表单
- 使用django的用户帐号登录 openfire
- 使用django的用户帐号登录openfire
- python django 用户注册验证登录。。。
- 使用django-userena搭建用户登录系统
- Django连接Postgresql时用户登录配置
- Django实战之用户验证登录
- 07+. Django用户登录验证系统和登录注销
- SGU 140 Integer Sequences(拓展欧几里得)
- Nexus OSS的安装、使用
- C++primer[习题][第一章][21-25]
- Hdu今夕何夕 (2017"百度之星"程序设计大赛
- 类的无参方法_学习笔记
- Django建教育平台(七)--用户登录
- ReactNative报错,错误解决
- 架构师日记——使用CLI管理Varnish
- file
- 第三章 Thread Synchronization Utilities(线程同步工具类)【上】
- Home Work
- java.lang.ClassNotFoundException:(新建的servlet无法找到class文件)
- 面试百战百答-无线通信专业001-RSRP
- Largest Submatrix of All 1’s (单调队列)