Django基礎04-day19
阿新 • • 發佈:2017-09-12
一個 2周 size cut http請求 rfi something con www
寫在前面
上課第19天,打卡:
忠於你的理想,別想生活妥協,讓掙紮變得有意義!
################ # 2017-09-03 - 課上筆記 ################ class day19: def __init__(): pass def do_homework(): pass def do_my_project(): pass ‘‘‘Django 回顧‘‘‘ - http請求周期 瀏覽器(socket客戶端) 2.socket.connect(ip,port) 進行連接 3.socket.send("http://www.qq.com/index.html...") url + data 遵循的規則:http協議 請求頭 請求體 請求頭和請求體使用 ‘\r\n\r\n‘ 分隔,前面是請求頭,後面是請求體 GET請求: "GET /index.html?key=1... Http/1.1\r\nhost:www.qq.com\r\ncontent-type:application/json\r\n\r\n" POST請求:"POST /index.html Http/1.1\r\nhost:www.qq.com\r\ncontent-type:application/json\r\n\r\nname=alex&pwd=123" 6.獲取響應 響應頭,響應體 = data.split("\r\n\r\n") 響應頭之間用 ‘\r\n‘ 分隔 7.斷開連接 nginx(socket服務端) 1.server.run(),監聽IP和PORT 4.server.recv() 請求頭,請求體 = data.split("\r\n\r\n") request.POST.get(‘name‘) 即是從 請求體 裏取值 5.服務端進行響應: conn.send(‘......‘) 遵循的規則:http協議 響應頭 響應體 7.斷開連接 總結: a.Http請求中本質都是字符串 b.Http請求是短連接(請求 -> 響應 -> 斷開連接) c.請求和響應都有頭和體 請求:請求頭‘\r\n\r\n‘請求體 響應:響應頭‘\r\n\r\n‘響應體 由於需要處理繁瑣http的解析和封裝處理工作,所以web框架應運而生 web框架 - Django socket(wsgiref) django沒有自己寫socket 解析和封裝http請求 django-admin startproject mysite cd mysite python manage.py startapp app01 coding...(*****) python manage.py runserver ip:port ‘‘‘寫代碼‘‘‘ - 路由系統 /login/ func name=‘f1‘ /login/\d+/ func name=‘f2‘ /login/(?P<n>\d+)/ func name=‘f3‘ /login/\d+/ include(‘app01.urls‘) - 視圖函數 def index(request): request.GET request.body 原生的請求體 request.POST 轉換後的請求體字典 如果請求頭中content-type=urlencode-form... 才將request.body轉換成字典 - 可能有值 - 也可能沒有值 request.method request.Meta request.GET.get() request.GET.getlist() 前端多選的情況,如多個作者 request.POST.get() request.POST.getlist() return HttpResponse(‘字符串/字節‘) return render(request,"html路徑",locals()) return redirect("url") - 模板 for if 繼承 filter,simple_tag - Models操作 - 創建表 - models.xxx.objects.create(name="xxxx") - models.xxx.objects.create(**dic) - models.xxx.objects.filter(id__gt=1).delete() - models.xxx.objects.filter(id=1) - models.xxx.objects.exclude(id=5) 取出id不等於5的 - models.xxx.objects.filter(id=1).update(name=‘ddd‘) - models.xxx.objects.filter(id=1).update(**dic) queryset --> [對象,對象...] objs = models.xxx.objects.all() queryset --> [{},{}...] objs = models.xxx.objects.all().values() queryset --> [(),()...] objs = models.xxx.objects.all().values_list() demo1 業務線表 bussiness_unit id name 主機表 serverinfo id host port bs(業務線對象) objs = modesl.serverinfo.objects.all() for row in objs: print(row.id) print(row.host) print(row.port) print(row.bs.name) 外鍵,拿到業務線的名字 objs = modesl.serverinfo.objects.all().values("id","host","port","bs__name") for row in objs: print(row[‘host‘]) print(row[‘bs__name‘]) demo2 (userinfo 和 bussiness_unit 是多對多關系) 用戶表 userinfo id user pwd email mm(ManyToMany) 業務線表 bussiness_unit id name 主機表 id host port bs(業務線對象) 用戶業務線關系表 ***** id user_id bs_id obj = models.user.objects.filter(user=‘alex‘).first() obj.mm.add(1) obj.mm.add(11) - 通過用戶對象查所負責的所有業務線對象 obj = models.user.objects.filter(user=‘alex‘).first() queryset = obj.mm.all() 拿到alex負責的所有業務線 -> [業務線對象,業務線對象...] for row in queryset: print(row.id) print(row.name) - 通過業務線反查對應有哪些人負責? (***反查*** 表名_set) obj = models.bussiness_unit.objects.filter(name=‘二手車‘).first() queryset = obj.userinfo_set.all() 拿到負責二手車業務線的用戶對象 -> [用戶對象,用戶對象...] for row in queryset: print(row.user) print(row.pwd) 總結: 1.多對多關系建在哪張表上都可以; 2.如果建在userinfo表上,那麽通過用戶對象查所負責的bs對象列表就直接用 obj.mm.all() 方便了 userinfo對象,但是bs對象反查userinfo就得用 userinfi_set.all() ================================================================== 今日內容: 1.登錄 - 密碼加密,對密碼進行比較 - 用戶登錄之後才能訪問某些頁面 2.cookie是什麽? - 保存在客戶端瀏覽器上的鍵值對 {k:v} - cookie依附在請求頭或者響應頭中 - 瀏覽器發送請求時會自動攜帶所訪問網站對應的cookie - 應用 - 實現登錄 - 投票 - 每頁顯示10條/20條... - 使用 - 設置 response = redirect(‘/index/‘) response.set_cookie(‘my_cookie‘,md5.encrypt(‘xxx‘)) return response key, value=‘‘, max_age=None, 超時時間:秒數 expires=None, 超時時間:截止日期 path=‘/‘, cookie在哪個url裏生效 : 訪問指定url時才能讀取到cookie, ‘/‘ 表示全部頁面都可以 domain=None, 當前域名或者二級域名 secure=False, https httponly=False response = redirect(‘/index/‘) # 設置cookie response.set_cookie(‘my_cookie‘,md5.encrypt(user)) return response # 設置cookie過期時間 import datetime deadline = datetime.datetime.utcnow() + datetime.timedelta(seconds=5) response.set_cookie(‘my_cookie‘,md5.encrypt(user),expires=deadline) response.set_cookie(‘my_cookie‘,md5.encrypt(user),max_age=5) - 獲取 ck = request.COOKIES.get(‘my_cookie‘) # 詳細代碼如下: ‘‘‘ # models.py from django.db import models # Create your models here. class UserInfo(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=64) email = models.EmailField(null=True) ‘‘‘ ‘‘‘ from django.shortcuts import render,HttpResponse,redirect from app01 import models from common import md5 # 判斷用戶是否登錄的裝飾器(通過cookie判斷) def auth(func): def inner(request,*args,**kwargs): ck = request.COOKIES.get(‘my_cookie‘) if not ck: return redirect(‘/login/‘) return func(request,*args,**kwargs) return inner @auth def index(request): user = request.COOKIES.get(‘my_cookie‘) print(request.COOKIES) # return HttpResponse("登錄成功") return render(request,‘index.html‘,locals()) def login(request): if "GET" == request.method: return render(request,‘login.html‘) else: user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) obj = models.UserInfo.objects.filter(username=user,password=md5.encrypt(pwd)).first() if obj: response = redirect(‘/index/‘) # 設置cookie過期時間 # import datetime # deadline = datetime.datetime.utcnow() + datetime.timedelta(seconds=5) # response.set_cookie(‘my_cookie‘,md5.encrypt(user),expires=deadline) # response.set_cookie(‘my_cookie‘,md5.encrypt(user),max_age=5) # 設置cookie response.set_cookie(‘my_cookie‘,user) return response else: return render(request,‘login.html‘,{‘msg‘:"用戶名或密碼錯誤"}) ‘‘‘ ‘‘‘ # login.html ... <form action="/login/" method="POST"> {% csrf_token %} <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交"><span style="color: red;">{{ msg }}</span> </form> ... # index.html ... <h1>{{ user }}</h1> ... ‘‘‘ ‘‘‘ # md5.py def encrypt(pwd): import hashlib obj = hashlib.md5() obj.update(pwd.encode(‘utf-8‘)) data = obj.hexdigest() return data if __name__ == ‘__main__‘: print(encrypt(‘123‘)) ‘‘‘ 3.session 是保存在服務器端的鍵值對 {k:v} 依賴cookie Django默認支持Session,並且默認是將Session數據存儲在數據庫中,即:django_session 表中。 更多參考:http://www.cnblogs.com/wupeiqi/articles/5246483.html 生成隨機字符串,並將其當做cookie發送給客戶端 服務端設置隨機字符串作為key,自己設置一些{}:request.session[‘my_session_key‘] = user - 設置session request.session[‘yyy‘] = user return redirect(‘/index/‘) - 獲取session # 裝飾器 def auth(func): def inner(request,*args,**kwargs): ck = request.session.get(‘yyy‘) if not ck: return redirect(‘/login/‘) return func(request,*args,**kwargs) return inner - 清空session request.session.clear() http://www.cnblogs.com/wupeiqi/articles/5246483.html SESSION_ENGINE = ‘django.contrib.sessions.backends.db‘ # 引擎(默認) 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,默認修改之後才保存(默認) # 詳細代碼如下: ‘‘‘ from django.shortcuts import render,HttpResponse,redirect from app01 import models from common import md5 # 判斷用戶是否登錄的裝飾器(通過session判斷) def auth(func): def inner(request,*args,**kwargs): ck = request.session.get(‘my_session_key‘) if not ck: return redirect(‘/login/‘) return func(request,*args,**kwargs) return inner @auth def index(request): user = request.session.get(‘my_session_key‘) return render(request,‘index.html‘,locals()) @auth def order(request): return render(request,‘order.html‘) # 登出view def logout(request): # 用戶登出後清空session request.session.clear() return redirect(‘/index/‘) def login(request): if "GET" == request.method: return render(request,‘login.html‘) else: user = request.POST.get(‘user‘) pwd = request.POST.get(‘pwd‘) obj = models.UserInfo.objects.filter(username=user,password=md5.encrypt(pwd)).first() if obj: # 設置session request.session[‘my_session_key‘] = user return redirect(‘/index/‘) else: return render(request,‘login.html‘,{‘msg‘:"用戶名或密碼錯誤"}) ‘‘‘ ‘‘‘ # urls.py from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^login/‘, views.login), url(r‘^logout/‘, views.logout), url(r‘^index/‘, views.index), url(r‘^order/‘, views.order), ] ‘‘‘ ‘‘‘ # login.html ... <form action="/login/" method="POST"> {% csrf_token %} <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交"><span style="color: red;">{{ msg }}</span> </form> ... # index.html ... <h1>{{ user }}</h1> ... # order.html ... <body> <h1>歡迎登錄:{{ request.session.my_session_key }}</h1> <a href="/logout/">註銷</a> </body> ... ‘‘‘ 4.csrf 跨站請求偽造 <form action="/login/" method="POST"> {% csrf_token %} <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交"><span style="color: red;">{{ msg }}</span> </form> {% csrf_token %} 在瀏覽器裏默認就是一個隱藏的input標簽,如下所示: <form action="/login/" method="POST"> <input type=‘hidden‘ name=‘csrfmiddlewaretoken‘ value=‘T2Ub1TacecIsEsKJvoUvB3xNSwrEGT0NajwGeO6y58mp1IseYVLL3FBnXtOT3WgW‘ /> <input type="text" name="user"> <input type="text" name="pwd"> <input type="submit" value="提交"><span style="color: red;"></span> </form> 而 {{ csrf_token }} 這個就是這個隱藏標簽的value值 跨站請求的漏洞: <form method="POST" action="http://www.icbc.com.cn/icbc/"> <input type="text" name="from" style="display: none;" value="A的卡號"> <input type="text" name="to" style="display: none;" value="黑客的卡號"> <input type="text" name="money" style="display: none;" value="1000000000"> <input type="submit" name="" value="點我"> </form> {% csrf_token %} # 首先不提交 csrf_token 的情況:報錯403,CSRF verification failed. Request aborted. <form id="my_form" action="/login/" method="POST"> <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/bootstrap.min.js" %}"></script> <script> function ajaxSubmit() { $.ajax({ url:‘/show/‘, type:‘POST‘, data:{ ‘user‘:$(‘#my_form input[name="user"]‘).val(), ‘email‘:$(‘#my_form input[name="email"]‘).val() }, success:function (data) { console.log(data); } }) } </script> # 註意一點: # 如果form表單不寫action,則默認提交到當前頁面 ajax提交csrf_token的幾種方式: # 方式1 <form id="my_form" action="/show/" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/bootstrap.min.js" %}"></script> <script> function ajaxSubmit() { $.ajax({ url:‘/show/‘, type:‘POST‘, data:{ ‘user‘:$(‘#my_form input[name="user"]‘).val(), ‘email‘:$(‘#my_form input[name="email"]‘).val(), ‘csrfmiddlewaretoken‘:$(‘input[name="csrfmiddlewaretoken"]‘).val() }, success:function (data) { console.log(data) } }) } </script> # 方式2 只能寫在模板裏 <body> <form id="my_form" action="/show/" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/bootstrap.min.js" %}"></script> <script> function ajaxSubmit() { $.ajaxSetup({ data: {‘csrfmiddlewaretoken‘:‘{{ csrf_token }}‘} }); $.ajax({ url:‘/show/‘, type:‘POST‘, data:{ ‘user‘:$(‘#my_form input[name="user"]‘).val(), ‘email‘:$(‘#my_form input[name="email"]‘).val() }, success:function (data) { {# do something...#} } }) } </script> </body> # 後端得到的數據: 類型:<class ‘django.http.request.QueryDict‘> 數據:<QueryDict: {‘csrfmiddlewaretoken‘: [‘raZNrc77aQn7cr5Wr6gtTgOaTdNWZKF0HmAfN6kqlGzmyrr4Dw7DUcSVQ6ZHcFoQ‘], ‘email‘: [‘[email protected] om‘], ‘user‘: [‘borui‘]}> # 方式3 只能寫在模板裏 <form id="my_form" action="/show/" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/bootstrap.min.js" %}"></script> <script> function ajaxSubmit() { $.ajax({ url:‘/show/‘, type:‘POST‘, data:{ ‘user‘:$(‘#my_form input[name="user"]‘).val(), ‘email‘:$(‘#my_form input[name="email"]‘).val(), ‘csrfmiddlewaretoken‘:"{{ csrf_token }}" }, success:function (data) { {# do something...#} } }) } </script> 這種方法,循環form表單,把很多input值拿出來組成字典, 然而實際上POST請求最後是需要轉換成字符串放到請求體中發給後端的,實際上的字符串如下: ‘csrfmiddlewaretoken=ouyWxV86TJWMttyLwzRkORIcqXjInlDREG9oTPlp4z81PtUTIZIuPNMXnQvtAgmH&user=love&email=love%40qq.com‘ 所以,如果ajax裏的data字段如果寫成一個字典,那麽就需要一個轉成字符串的過程; 如果直接寫成字符串,也是可以的; $(‘#my_form‘).serialize() 這個方法就可以把form表單裏所有的值(包含隱藏的csrf標簽)拼接成一個字符串; # 方法4: <form id="my_form" action="/show/" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/bootstrap.min.js" %}"></script> <script> function ajaxSubmit() { $.ajax({ url:‘/show/‘, type:‘POST‘, data:$(‘#my_form‘).serialize(), success:function (data) { console.log(data) } }) } </script> ‘‘‘ 以上4中方法都是把csrf_token放入 請求體 裏傳遞給後端 ‘‘‘ # 方法5 把csrftoken對應的值方到 請求頭 裏,傳遞給後端,這樣也可以通過csrf驗證 首先引入 jquery.cookie.js 插件 然後通過 $.cookie(‘csrftoken‘) 則可以獲取到csrftoken對應的值 這種方法,是把csrftoken對應的值放到請求頭裏,必須按照這個格式:headers:{‘X-CSRFToken‘: $.cookie(‘csrftoken‘)} 這種情況,請求體的內容可以隨便寫; <form id="my_form" action="/show/" method="post"> {% csrf_token %} <input type="text" name="user"> <input type="email" name="email"> <button onclick="ajaxSubmit()">Ajax提交</button> </form> <script src="{% static "js/jquery-3.2.1.min.js" %}"></script> <script src="{% static "js/jquery.cookie.js" %}"></script> <script src="{% static "js/bootstrap.js" %}"></script> <script> function ajaxSubmit() { $.ajax({ url:‘/show/‘, type:‘POST‘, data:{‘k1‘:‘v1‘,‘k2‘:‘v2‘}, headers:{‘X-CSRFToken‘: $.cookie(‘csrftoken‘)}, success:function (data) { console.log(data) } }) } </script> 總結: 基於ajax提交form表單,發送csrf驗證的方式裏 最常用的就是 data:$(‘#my_form‘).serialize() 和 headers:{‘X-CSRFToken‘: $.cookie(‘csrftoken‘)} 另外: 關於csrf有兩個裝飾器:from django.views.decorators.csrf import csrf_exempt,csrf_protect ‘django.middleware.csrf.CsrfViewMiddleware‘, # 開啟則表示全站都使用csrf驗證,而csrf_exempt這個裝飾器則表示哪些view可以不使用csrf # 如果不開啟,則表示全站都不使用csrf驗證,而csrf_protect這個裝飾器則表示哪些view可以使用csrf
# 自定義分頁模塊 request.path_info
Django基礎04-day19