2、session
一、session与cookie对比
二、session基本原理及流程
三、session服务器操做(获取值、设置值、清空值)
四、session通用配置(在配置文件中)
五、session引擎配置(db、cache、file、cookie加密)
3、CSRF
一、csrf原理-form提交及ajax提交
二、csrf全局与局部应用配置
4、中间件生命周期
一、process_request、process_response
下面本身建立一个中间件
二、process_view
三、其余
1、内容回顾html
Cookie:保存在用户浏览器端的键值对 python
本地能够修改;若是有敏感信息,能够被看到。jquery
基于cookie作用户验证时,敏感信息不适合放在cookie中
把存储压力放到每一个客户端上,对于服务器端压力小了。ajax
Session:保存在服务器端的键值对redis
服务端:保存键值对{'随机字符串':{……用户信息……}}
,经过cookie保存随机字符串到客户端上。数据库
使用session前:先执行 python manage.py makemigrations
, python manage.py migrate
,由于默认Django session 保存在数据库中的django_session表中。django
session 设置值浏览器
request.session['is_login'] = True
Django会执行一下操做# 生成随机字符串 # 写到用户浏览器cookie # 保存到session中 # 在随机字符串对应的字典中设置相关内容……
session 获取值缓存
request.session['is_login']:
执行如下操做# 获取当前用户的随机字符串 # 根据随机字符串获取对应信息
python manage.py migrate
urls.py服务器
url(r'^login/', views.login), url(r'^index/', views.index), url(r'^logout/$', views.logout),
views.py
def login(request): if request.method == "GET": return render(request,'login.html') elif request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') if user == 'root' and pwd == "123": # session中设置值 # 生成随机字符串 # 写到用户浏览器cookie # 保存到session中 # 在随机字符串对应的字典中设置相关内容…… request.session['username'] = user request.session['is_login'] = True if request.POST.get('rmb',None) == '1': # 超时时间 request.session.set_expiry(10) return redirect('/index/') else: return render(request,'login.html') def index(request): # 获取当前用户的随机字符串 # 根据随机字符串获取对应信息 if request.session.get('is_login',None): return HttpResponse(request.session['username']) else: return HttpResponse("请登陆……") def logout(request): # del request.session['username'] request.session.clear() # 清除session,注销 return redirect('/login/')
login.html
<body> <form action="/login/" method="POST"> <input type="text" name="user" /> <input type="text" name="pwd" /> <input type="checkbox" name="rmb" value="1" /> 10秒免登陆 <input type="submit" value="提交" /> </form> </body>>
index.html
<body> <h1>欢迎登陆:{{ username }}, {{ request.session.username }}</h1> <!---------- 这里不用使用后台模板传值,使用session也能获取到用户名 --------------> <a href="/logout/">注销</a> </body>
# 获取、设置、删除Session中数据 request.session['k1'] # 获取 request.session.get('k1',None) request.session['k1'] = 123 # 设置 request.session.setdefault('k1',123) # 存在则不设置 del request.session['k1'] # 删除 # 全部 键、值、键值对 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 获取用户session的随机字符串 request.session.session_key # 将全部Session失效日期小于当前日期的数据删除 request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否存在 request.session.exists("session_key") # 删除当前用户的全部Session数据 request.session.delete("session_key") request.session.clear() # 比delete用法更简单,注销的时候可使用 # 设置超时时间 (默认session超时时间是两周) request.session.set_expiry(value) # * 若是value是个整数,session会在些秒数后失效。 # * 若是value是个datatime或timedelta,session就会在这个时间后失效。 # * 若是value是0,用户关闭浏览器session就会失效。 # * 若是value是None,session会依赖全局session失效策略。
settings.py
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,默认修改以后才保存(默认) # 这个好。settings里设为true,超时时间按照最后一次客户端请求计算,如上按照最后一次请求以后10秒失效。
Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:
# 数据库Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) # 缓存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也能够是memcache),此处别名依赖缓存的设置 # 链接memcache 的配置,缓存部分会提到。不支持redis,连它须要安装插件 # 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = os.path.join(BASE_DIR, 'cache') # 放到cache目录下 SESSION_FILE_PATH = None # 缓存文件路径,若是为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T # 缓存+数据库Session SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 # 加密cookie Session (都放到cookie里面,只是作了加密处理) SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
以前提到的xss攻击:网站评论里等容许别人写js的时候,别人进行的恶意操做。csrf相似。
CSRF的防御一般有两种方式,一个是经过Challenge-Response的方式,例如经过Captcha和从新输入密码等方式来验证请求是否伪造,但这会影响用户体验,相似银行付款会采用这样的方式。另外一种是经过随机Token的方式,多数Web系统都会采用这种方式,Django也是用的这种。
客户端get请求时,django会生成随机字符串给客户,当客户端提交form表单的时候,若是没有随机字符串,则django不容许,报403错误。
form提交数据须要带随机字符串过去,Ajax提交也须要带着过去。ajax带哪的值?
加上{% csrf_token %}
在html form里生成了一个,在也生成了一份。浏览器审查元素 –> Network –> Cookies 里也能找到随机字符串。
因此ajax提交的时候,只须要把cookie里的随机字符串拿到,放到请求头里面发过去就能够了
后台获取随机字符串的key,key是什么值? x-CSRFtoken
login.html
<body> <!-- form 提交 --> <form action="/login/" method="POST"> <!-- 生成 csrf 的随机字符串 --> <!-- {{ csrf_token }} --> {% csrf_token %} <!--html里会自动生成隐藏input框--> <input type="text" name="user" /> <input type="text" name="pwd" /> <input type="checkbox" name="rmb" value="1" /> 10秒免登陆 <input type="submit" value="提交" /> <input id="btn" type="button" value="Ajax提交" /> </form> <script src="/static/jquery-1.12.4.js"></script> <script src="/static/jquery.cookie.js"></script> <script> $(function(){ // ajax 提交 $.ajaxSetup({ // 对整个页面全部的ajax操做作个配置 beforeSend: function(xhr,settings){ // 发送ajax前的操做 xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken')); } }); $('#btn').click(function () { $.ajax({ url: '/login/', type:"POST", data: {'user': 'root', 'pwd': '123'}, // 这种方式加请求头,每一个操做都加麻烦一些,因此使用上面的 ajaxSetup 里加 // headers: {'X-CSRFtoken': $.cookie('csrftoken')}, success:function(arg){ } }) }); }) </script> </body>
这里ajax提交,在浏览器审查元素、network里看效果。
settings里面,容许csrf验证,那么就是对全局都进行验证。若是个别的方法不须要使用,怎么单一配置?
django为用户实现防止跨站请求伪造的功能,经过中间件 django.middleware.csrf.CsrfViewMiddleware
来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
@csrf_protect
,为当前函数强制设置防跨站请求伪造功能,即使settings中没有设置全局中间件。@csrf_exempt
,取消当前函数防跨站请求伪造功能,即使settings中设置了全局中间件。注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
对于ajax中,采用ajaxSetup
方式也是全局都加,好比get方式是不须要的,能够以下配置
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) { // settings 会获取到ajax里面的全部配置 if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); function Do(){ $.ajax({ url:"/app01/test/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); }
settings里的 MIDDLEWARE 都是一个一个的中间件。客户端请求,先通过一排一排的中间件到达views,以后再经过中间件返回给客户端。而经过中间件都是调用中间件的某个方法、
随便建立一个目录middle,
middle/m.py
from django.utils.deprecation import MiddlewareMixin class Row1(MiddlewareMixin): def process_request(self, request): print("中间件1") def process_response(self, request, response): print("中间件1返回") return response # 参数里的 response :就是views里面返回的值,因此要继续返回一下,不然客户端收不到数据 from django.shortcuts import HttpResponse class Row2(MiddlewareMixin): def process_request(self, request): print("中间件2") # return HttpResponse("禁止你访问") def process_response(self, request, response): print("中间件2返回") return response class Row3(MiddlewareMixin): def process_request(self, request): print("中间件3") def process_response(self, request, response): print("中间件3返回") return response
settings.py
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', 'middle.m.Row1', 'middle.m.Row2', 'middle.m.Row3', ]
views.py
def test(request): print("最终返回信息") return HttpResponse("OK")
中间件里面的参数request里接受的数据和views里接受的数据是同样的,因此从里面取值能够作相应的判断处理,允不容许数据经过。
好比上面的示例:中间件row2,process_request,里返回数据,则会在同级的process_response里开始返回数据给客户端了。
注意:这是在Django1.10版本才这样的,以前版本:row2返回数据,会在最底部的response开始网上返回数据,这里是row3。
因此中间件是对全部的请求作统一操做,好比数据校验、黑名单过滤
以下:每一个中间件类中中加入以下方法:
class Row1(MiddlewareMixin): def process_request(self, request): print("中间件1") def process_view(self, request, view_func, view_func_args, view_func_kwargs): # view_func 对应 views函数,view_func_args、kwargs 对应 views里的参数、 print("中间件1view") def process_response(self, request, response): print("中间件1返回") return response
请求顺序以下:用户请求 –> 每一个中间件的request –> 到达urls路由匹配,匹配成功后 –> 折回每一个中间件的view –> views –> 经过response返回
def process_exception(self, request, exception): if isinstance(exception, ValueError): return HttpResponse("出现异常") # 异常处理 views函数里出错了,执行这里,如views里 int('lgeng')
views函数若是出现异常,返回会找exception方法,一级一级往上找,若是有处理返回,若是都没有处理就直接返回报错了。
process_template_response(self,request,response) # 若是views中的函数返回的对象中,具备render方法,执行这个方法。
一、基本生命周期
二、URL
/index/ index /list/(\d+) index /list/(\d+) name='li' index /list/(\d+) include index
三、views
# 全部内容的原生值 request.body # 全部的post请求,都会放到body里面传过去 request.POST # 从request.body中提取 request.GET # 从request.body中提取 request.FILES request.xxxx.getlist # 请求头内容 request.Meta request.method(POST,GET,PUT) request.path_info request.COOKIES …… # 返回数据 ######### return HttpResponse # 支持返回字符串 和 bytes类型 return render # 渲染页面 return redirect # 跳转 # 返回cookie ## response = HttpResponse('ok') response.set_cookie() return response # 把cookie,放到响应头里面,客户端浏览器去响应头里面获取。。因此也能设置响应头内容 response['name'] = 'lgeng'
四、Model操做(原生Sql也能够)
# 表内容操做: models.TB.objects.create() obj = models.TB(..) obj.save() models.TB.objects.all()[7:10] # 切片 models.TB.objects.update() models.TB.objects.filter() models.TB.objects.delete models.TB.objects.values models.TB.objects.values_list models.TB.objects.get models.TB.objects.filter().update() models.TB.objects.filter().first() models.TB.objects.filter(**{}).count() models.TB.objects.filter(双下划线跨表) models.TB.objects.filter(id__gte=1) models.TB.objects.exclude(id__lt=1) models.TB.objects.filter(id_in=[1,2,3]) # id__in # 多对多 obj.set obj.add([1,2,3]) obj.add(1,2,3) obj.remove([1,2,3]) obj.clear() models.TB.objects.all() [obj,obj] obj.fk.name models.TB.objects.all().order_by('') models.TB.objects.distinct() ## 跨表操做 ########### class A: name ... # 而A表操做B表,经过表名+‘_set’ --> b_set class B: caption ... fk = ForignKey(A) # B表操做A表,经过 fk.
五、模板语言
# 基本操做 def func(request): return render(request,'index.html',{'val':[1,2,3]}) # index.html 里 <h1>{{ val.0 }}</h1> # 继承 extends "layout.html" # include 组件 # simpli_tag, filter
转载请务必保留此出处:http://www.cnblogs.com/lgeng/articles/7365891.html
<!-- END -->
《版本说明》: 本文转自 -- http://blog.csdn.net/fgf00/article/details/54299199