目录html
因为HTTP协议是无状态的,没法记住用户是谁,这样咱们在每一次登录的时候,都要从新输入密码,甚至若是不设置cookie,网页可能都请求不了前端
保存在客户端浏览器上的键值对python
是服务端设置在客户端浏览器上的键值对,也就意味着浏览器其实能够拒绝服务端的命令。默认状况下,浏览器都是直接让服务端设置键值对的面试
在操做开始以前咱们须要对三板斧进行变形ajax
obj1 = HttpResponse() return obj1 obj2 = render() return obj2 obj3 = redirect() return obj3
obj1.set_cookie()
request.COOKIES.get()
obj1.delete_cookie()
直接上代码:数据库
def login(request): # print(request.path_info) # 只拿url 不拿get请求携带的额外参数 # print(request.get_full_path()) # 都拿 if request.method == "POST": username = request.POST.get('username') password = request.POST.get('password') if username == 'yjy' and password == '123': old_path = request.GET.get('next') if old_path: # 保存用户登陆状态 obj = redirect(old_path) else: obj = redirect('/home/') obj.set_cookie('name', 'yjy') # 让客户端浏览器 记录一个键值对 # obj.set_cookie('name','jason',max_age=5) # 让客户端浏览器 记录一个键值对 return obj return render(request, 'login.html') from functools import wraps #装饰器修复技术 def login_auth(func): @wraps(func) def inner(request, *args, **kwargs): if request.COOKIES.get('name'): res = func(request, *args, **kwargs) return res else: target_url = request.path_info return redirect('/login/?next=%s' % target_url) return inner @login_auth def home(request): # 校验用户是否登陆 # if request.COOKIES.get('name'): # return HttpResponse('我是主页 只有登陆了才能看') # return redirect('/login/') return HttpResponse('我是主页 只有登陆了才能看') @login_auth def index(request): return HttpResponse('我是index页面 也须要用户登陆以后才能看') @login_auth def xxx(request): return HttpResponse('xxx页面 也是须要登陆了以后才能看') @login_auth def logout(request): obj = redirect('/login/') obj.delete_cookie('name') #注销以后删除cookie return obj
保存在服务器上的键值对django
django session默认的过时时间是14天后端
request.session['key'] = value #仅仅只会在内存产生一个缓存
三步骤:浏览器
session_key session_data date
随机字符串1 数据1 ...
随机字符串2 数据2 ...
随机字符串3 数据3 ...缓存
def set_session(request): request.session['username'] = 'yjy' request.session.set_expiry(value=0) #session在关闭浏览器后消失 return HttpResponse("设置session")
request.session..get('key')
三步骤:
request.session
,若是对不上 那么request.session
就是空session
表中的一条记录针对一个浏览器,同一台电脑上,不一样的浏览器来,才会有不一样的记录
def get_session(request): print(request.session.get('username')) return HttpResponse('获取session')
delete:删除服务端的
request.session.delete()
flush:浏览器和服务端所有删除
request.session.flush()
def delete_session(request): # request.session.delete() #删除服务端的session request.session.flush() #两个端的session都会删除 return HttpResponse("删除session")
request.session.set_expiry(value)
value
为整数,session
会在数秒后消失(以秒为单位)value
为 datatime或者timedelta时, session
会在这个时间后消失value
为0,session
会在关闭浏览器后消失value
为None,session
会依赖全局session
失效策略后端
from django.shortcuts import render, HttpResponse, redirect # Create your views here. def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == "yjy" and password == "123456": # 设置session值 request.session['username'] = username # 获取跳到登录以前的url next_url = request.GET.get("next") if next_url: return redirect(next_url) else: return redirect('/index/') return render(request, "login.html") # 装饰器 from functools import wraps def check_login(func): @wraps(func) def inner(request, *args, **kwargs): next_url = request.get_full_path() print(next_url) if request.session.get('username'): return func(request, *args, **kwargs) else: return redirect(f"/login/?next={next_url}") #http://127.0.0.1:8000/login/?username=yjy&password=123456 return inner @check_login def index(request): # request.session.get("username", None) return HttpResponse('我是index页面 须要用户登陆以后才能看')
前端:
<form action="" method="post"> {% csrf_token %} <p>username:<input type="text" name="username"></p> <p>password:<input type="text" name="password"></p> <button><input type="submit"></button> </form>
最终结果是这样子的
提交数据以后的显示
数据库中session的显示
用户访问频率限制
用户是不是黑名单 白名单
全部用户登陆校验
只要是涉及到网址全局的功能 中间件是不二之选
咱们先要作好相应的数据准备
1.新建一个文件夹 里面新建一个任意名称的py文件
里面写类 固定继承
from django.utils.deprecation import MiddlewareMixin class MyMiddle(MiddlewareMixin): ...
2.去配置文件注册到中间件配置中
须要手写字符串的路径
'app01.mymiddleware.myaabb.MyMiddle1' 'app02.mymiddleware.myaabb.MyMiddle2'
请求来的时候 会从上往下依次通过每个中间件里面process_request
,一旦里面返回了HttpResponse
对象那么就再也不日后执行了 会执行同一级别的process_response
def process_request(self,request): print('我是第一个自定义中间件里面的process_request方法') return HttpResponse("我是第一个自定义中间件里面的HttpResponse对象返回值") # 直接原地返回
响应走的时候 会从下往上依次通过每个中间件里面的process_response
def process_response(self,request,response): # response就是要返回给用户的数据 print("我是第一个自定义中间件里面的process_response方法") return response #只要有response参数,就必须给他返回
路由匹配成功以后,执行视图函数以前触发
当视图函数出现异常(bug)的时候自动触发
当视图函数执行完毕以后而且返回的对象中含有render方法的状况下才会触发
写form表单以前只须要加上{% csrf_token %}
第一种: 本身再页面上先经过{% csrf_token %}获取到随机字符串 而后利用标签查找
data:{'username':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
第二种:
data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
第三种:拷贝js文件
#这个东西在中间件的官网上拷贝就好了 function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('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); } } });
原理:
你写的form表单中 用户的用户名 密码都会真实的提交给银行后台
可是收款人的帐户却不是用户填的 你暴露给用户的是一个没有name属性的input框
你本身提早写好了一个隐藏的带有name和value的input框
后端
def transfer(request): if request.method == 'POST': username = request.POST.get('username') target_user = request.POST.get('target_user') money = request.POST.get('money') print('%s 给 %s转了%s钱' % (username, target_user, money)) return render(request, 'transfer.html')
正儿八经网站前端
<form action="" method="post"> <p>username:<input type="text" name="username"></p> <p>target_user:<input type="text" name="target_user"></p> <p>money:<input type="text" name="money"></p> <input type="submit"> </form>
钓鱼网站前端
<form action="http://127.0.0.1:8000/transfer/" method="post"> <p>username:<input type="text" name="username"></p> <p>targer_user:<input type="text"></p> <p><input type="text" name="target_user" value="jason" style="display: none"></p> <p>money:<input type="text" name="money"></p> <input type="submit"> </form>
只要是用户想要提交post请求的页面 我在返回给用户的时候就提早设置好一个随机字符串当用户提交post请求的时候 我会自动先取查找是否有该随机字符串
若是有 正常提交,若是没有 直接报403
以上仅仅是一个思路,仍是须要咱们用代码去实现,具体的实现方法就是在里面注入中间件。
先要导入模块
from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt,name='dispatch') class MyCsrf(View):
@method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): return super().dispatch(request,*args,**kwargs) def get(self,request): return HttpResponse('hahaha')
@method_decorator(csrf_protect,name='post') class MyCsrf(View):
@method_decorator(csrf_protect) def dispatch(self, request, *args, **kwargs): return super().dispatch(request,*args,**kwargs) def get(self,request): return HttpResponse('hahaha')
@method_decorator(csrf_protect) def post(self,request): return HttpResponse('post'
''' py2: >>> print("hello", "world") ('hello', 'world') py3: >>> print("hello", "world") hello world py2:input_raw() py3:input() 1/2的结果 py2:返回0 py3:返回0.5 py2:默认编码ascii py3:默认编码utf-8 字符串 py2:unicode类型表示字符串序列,str类型表示字节序列 py3::str类型表示字符串序列,byte类型表示字节序列 py2:函数用关键字global声明某个变量为全局变量,可是在嵌套函数中,想要给一个变量声明为非局部变量是无法实 现的。 py3:新增了关键字nonlocal,使得非局部变量成为可能 py2: int() # 整型 long() # 长整型 py3:没有long类型,只有int类型 py2:xrange 用法与 range 彻底相同,所不一样的是生成的不是一个list对象,而是一个生成器。 py3:将之前的range取消了,而将xrange从新命名成了range!因此咱们如今看到的range其实本质仍是xrange~。 py2: iteritems() 用于返回自己字典列表操做后的迭代器【Returns an iterator on allitems(key/value pairs) 】,不占用额外的内存。 py3: iteritems()方法已经废除了。在3.x里用 items()替换iteritems() ,能够用于 for 来循环遍历 '''
''' 可变不可变指的是内存中的值是否能够被改变, 可变:值得改变不会引发内存地址的改变 不可变:值得改变会引发内存地址的改变 不可变类型有数值、字符串、元组; 可变类型则是能够改变,主要有列表、字典。 '''
''' t = m #t=10 m = n #m=5 n = t #n=10 m,n = n,m #交叉赋值 '''