python周报第十九周
0.本周知识点总结
- Ajax验证
- django form 验证
- CSRF安全
- Cookie
- Session
- model 数据库ORM
1.Ajax验证
应用场景:验证用户输入是否合法
前端Ajax代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .error-tag { color: red; } </style> </head> <body> <div> <div> <input type="text" name="user" /> {# <span class="error-tag">aaa</span>#} </div> <div> <input type="password" name="pwd" /> </div> <input type="button" value="提交" onclick="DoSubmit();" /> </div> <script src="/static/jquery-1.12.4.js"></script> <script> function DoSubmit(){ {# 定义一个要传入后端的字典#} var input_dict = {}; {# 对所有的input进行循环#} $('input').each(function(){ {# 拿到每个input标签用户输入的值#} var v = $(this).val(); {# 拿到每个input标签的属性值#} var n = $(this).attr('name'); {# 拼接到字典,例如:{"username":"lk"}#} input_dict[n] = v; }); {# 先把所有的span标签都删除#} $("span").remove(); {# Ajax验证开始#} $.ajax({ {# url:/login/ POST请求 向后端传入字典 类型json#} url: '/login/', type: 'POST', data: input_dict, dataType : "json", {# 拿到后端返回的值,result就是拿到的值,判断是否登陆成功,根据判断进行处理#} success: function (result) { if (result.status) { location.href = "https://www.jd.com"; } else { {# 假如验证失败,result是返回的信息,result.message是总的报错信息,其中有pwd\user的,每一项有相应的message的信息#} $.each(result.message, function(k,v){ {# 创建span标签#} var tag = document.createElement("span"); tag.className = "error-tag"; {# span标签内容就是报错信息,v[0]就是报错信息#} tag.innerText = v[0].message; {# 利用拼接,根据属性,在input标签下方添加span标签.#} $('input[name="' + k + '"]').after(tag); }) } }, error: function () { } }) } </script> </body> </html>
2.Django Form 验证
应用场景:同样是用于用户认证,还<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .error-msg{ color: red; } </style> </head> <body> <form action="/login/" method="POST"> <div> <div>
obj1是字典,是后端传过来的form类生成的,然后obj1.user 是一个标签 {{ obj1.user }}
假如有报错,则生成错误标签 {% if obj1.errors.user %} <span class="error-msg">{{ obj1.errors.user.0 }}</span> {% endif %} </div> <div> {{ obj1.pwd }} <span class="error-msg">{{ obj1.errors.pwd.0 }}</span> </div> <div> {{ obj1.num }} <span class="error-msg">{{ obj1.errors.num.0 }}</span> </div> <div> {{ obj1.phone }} <span class="error-msg">{{ obj1.errors.phone.0 }}</span> </div> <div> {{ obj1.test }} <span class="error-msg">{{ obj1.errors.test.0 }}</span> </div> <input type="submit" value="提交" /> </div> </form> </body> </html>
后端代码:
import re # 定义手机号格式 def mobile_validate(value): mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') if not mobile_re.match(value): raise ValidationError('手机号码格式错误') # 定义一个form验证类,必须继承forms.Form # required输入非空限制,error_messages错误提示内容,min_length最小输入长度,max_length最大输入长度,validators可以加函数控制 # forms.类型 # 每个字段名比如user,就是前端input标签的name值.类型默认是text class LoginForm(forms.Form): user = forms.CharField(required=True, error_messages={'required': '用户名不能为空.'}, max_length=6) pwd = forms.CharField(required=True, min_length=6, max_length=10, error_messages={'required': '密码不能为空.', 'min_length': "至少6位"}) num = forms.IntegerField(error_messages={'required': '数字不能空.','invalid': '必须输入数字'}) phone = forms.CharField(validators=[mobile_validate, ],) #test = forms.CharField(widget=forms.Textarea(attrs={'class': 'c1'})) test_choices = ( (0, '上海'), (1, '背景'), ) # select标签里要写上里边的option,要以元组的形式带入 test = forms.IntegerField(widget=forms.Select(choices=test_choices)) def login(request): if request.POST: objPost = LoginForm(request.POST) # is_valid 判断输入是否合法 ret = objPost.is_valid() print("ret:", ret) if ret: print("clean:", objPost.clean()) print(objPost.clean()) print("user", objPost["user"]) else: from django.forms.utils import ErrorDict # 报错信息 print(type(objPost.errors),objPost.errors.as_json()) # obj1.errors pass print("objPost:", objPost) print("objPost,Type:", type(objPost)) print("objPost.user:", objPost["user"]) return render(request, 'login.html',{'obj1': objPost})
python的输出:
ret: False <class 'django.forms.utils.ErrorDict'> {"user": [{"code": "max_length", "message": "Ensure this value has at most 6 characters (it has 8)."}]} objPost: <tr><th><label for="id_user">User:</label></th><td><ul class="errorlist"><li>Ensure this value has at most 6 characters (it has 8).</li></ul><input id="id_user" maxlength="6" name="user" type="text" value="11111111" required /></td></tr> <tr><th><label for="id_pwd">Pwd:</label></th><td><input id="id_pwd" maxlength="10" minlength="6" name="pwd" type="text" value="dddddddddd" required /></td></tr> <tr><th><label for="id_num">Num:</label></th><td><input id="id_num" name="num" type="number" value="42222222" required /></td></tr> <tr><th><label for="id_phone">Phone:</label></th><td><input id="id_phone" name="phone" type="text" value="13111112222" required /></td></tr> <tr><th><label for="id_test">Test:</label></th><td><select id="id_test" name="test" required> <option value="0" selected="selected">上海</option> <option value="1">背景</option> </select></td></tr> objPost,Type: <class 'day19_app.views.LoginForm'> objPost.user: <input id="id_user" maxlength="6" name="user" type="text" value="11111111" required />
3.CSRF
当在settings.py中未注释这一行时,就会产生CSRF 安全中间件的审核。
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
如图:
这种情况可以分为三种解决方案:
1.注释掉那行配置,这个不多说
2.form表单验证,在前端代码加入:
<body> <form action="/csrf/" method="post"> {% csrf_token %} 加入这一行!!!!!! <input type="text" name="t1"/> <input type="submit" value="form提交"/> </form>
这时,在浏览器看前端代码就可以看到
这就相当于一层安全认证,当访问时,django会写入浏览器一些数据,如下次带着这个数据访问,就可通过,如没有数据,则会被拦截,这个一般是防止XSS攻击的。
3.Ajax验证。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/csrf/" method="post"> {% csrf_token %} <input type="text" name="t1"/> <input type="submit" value="form提交"/> </form> <input type="button" value="ajax提交" onclick="DoAjax();"/> <script src="/static/jquery-1.12.4.js"></script> <script src="/static/jquery.cookie.js"></script> <script> var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); {# 主函数#} function DoAjax(){ $.ajax({ url: "/csrf/", type: "POST", data : {"k1":"v1"}, success: function (data) { console.log(data); } }) } </script> </body> </html>
4.cookie
cookie是服务端写入浏览器的,这个要确保浏览器允许写入cookie。
1.设置cookie
后端代码:
def cookie(request): #打印请求cookie print(request.COOKIES) #返回前端页面 obj = render(request, 'cookie.html') #在浏览器设置cookie: "k3":"v3",path是只有在访问/cookie时能看到 obj.set_cookie('k3','v3',path='/cookie/') return obj
5.session
cookie是保存在客户端浏览器,session是保存在服务端
USER_LIST = ["lk", "liukai"] def session_login(request): if request.method == "POST": # 获取用户名和密码 u = request.POST.get("user") p = request.POST.get("pwd") if p == "123" and u in USER_LIST: # 在服务端设置session: "user" = "输入的用户名" request.session['user'] = u return redirect('/session_index/') return render(request, "session_login.html") # 登陆验证,验证服务端是否配置了session def auth(func): def inner(request, *args, **kwargs): user = request.session.get('user', None) print(user) if not user: return redirect('/session_login') return func(request, *args, **kwargs) return inner # 直接访问index页面,先验证session @auth def session_index(request): user = request.session.get('user') return render(request, "session_index.html", {"user": user}) def session_logout(request): del request.session["user"] return redirect("/session_login/")
前端代码 session_index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>欢迎:{{ user }}登录</h1> <a href="/session_logout/">注销</a> </body> </html>