s14_09_cookie session csrf
- Cookie
1、获取Cookie:
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
参数:
default: 默认值
salt: 加密盐
max_age: 后台控制过期时间
2、设置Cookie:
rep = HttpResponse(...) 或 rep = render(request, ...)
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...)
参数:
key, 键
value='', 值
max_age=None, 超时时间
expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
path='/', Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
domain=None, Cookie生效的域名
secure=False, https传输
httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
3、由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。
<script src='/static/js/jquery.cookie.js'></script>
$.cookie("list_pager_num", 30,{ path: '/' });
response = HttpResponse(a)
response.set_cookie()
return response
# cokies 通过响应头返回
response = HttpResponse(a)
response['name'] = ’alex‘
# 自己写响应头
- 示例:
user_info ={
'dachengzi':{'pwd':'123123'},
'kangbazi':{'pwd':'456789'}
}
def login(request):
if request.method=='GET':
return render(request,'login.html')
if request.method=='POST':
u = request.POST.get('username')
p = request.POST.get('pwd')
dic = user_info.get(u)
if not dic:
return render(request,'login.html')
if dic['pwd']== p:
res = redirect('/index/')
res.set_cookie('username',u)
return res
else:
return render(request,'login.html')
def index(request):
v = request.COOKIES.get('username')
if not v:
return redirect('/login/')
return render(request,'index.html',{'current_user':v})
def cookie(request):
request.COOKIES
request.COOKIES['username']
request.COOKIES.get('username')
response =render(request,'index.html')
response =redirect('/index/')
# 设置cockie,关闭浏览器失效
response.set_cookie('key','value')
# 设置cockie,n秒后失效
response.set_cookie('username','value',max_age=10)
# 设置cockie,截止时间失效
import datetime
current_date = datetime.datetime.utcnow()
current_date = current_date + datetime.timedelta(seconds=10)
response.set_cookie('username','value',expires=current_date)
# 应用:每页显示多少数量
response.set_cookie('username','value',path='/')
return response
- 用户认证装饰器
FBV:
def auth(func):
def inner(reqeust,*args,**kwargs):
v = reqeust.COOKIES.get('username111')
if not v:
return redirect('/login/')
return func(reqeust, *args,**kwargs)
return inner
@auth
def index(reqeust):
# 获取当前已经登录的用户
v = reqeust.COOKIES.get('username111')
return render(reqeust,'index.html',{'current_user': v})
CBV:
def auth(func):
def inner(reqeust,*args,**kwargs):
v = reqeust.COOKIES.get('username111')
if not v:
return redirect('/login/')
return func(reqeust, *args,**kwargs)
return inner
from django import views
from django.utils.decorators import method_decorator
# 仅对get
class Order(views.View):
@method_decorator(auth)
def get(self,reqeust):
v = reqeust.COOKIES.get('username111')
return render(reqeust,'index.html',{'current_user': v})
def post(self,reqeust):
v = reqeust.COOKIES.get('username111')
return render(reqeust,'index.html',{'current_user': v})
# 通过dispatch 对全部
class Order(views.View):
@method_decorator(auth)
def dispatch(self, request, *args, **kwargs):
return super(Order,self).dispatch(request, *args, **kwargs)
def get(self,reqeust):
v = reqeust.COOKIES.get('username111')
return render(reqeust,'index.html',{'current_user': v})
def post(self,reqeust):
v = reqeust.COOKIES.get('username111')
return render(reqeust,'index.html',{'current_user': v})
# 对全部方法
@method_decorator(auth,name='dispatch')
class Order(views.View):
def get(self,reqeust):
v = reqeust.COOKIES.get('username111')
return render(reqeust,'index.html',{'current_user': v})
def post(self,reqeust):
v = reqeust.COOKIES.get('username111')
return render(reqeust,'index.html',{'current_user': v})
- Session
基于Cookie做用户验证时:敏感信息不适合放在cookie中
a. Session原理
Cookie是保存在用户浏览器端的键值对
Session是保存在服务器端的键值对
b. Cookie和Session对比
c. Session配置(缺少cache)
d. 示例:实现两周自动登陆
- request.session.set_expiry(60*10)
- SESSION_SAVE_EVERY_REQUEST = True
PS: cookie中不设置超时时间,则表示关闭浏览器自动清除
- session依赖于cookie
- 服务器session
request.session.get()
request.session[x] = x
request.session.clear()
- 配置文件中设置默认操作(通用配置):
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过期(默认)
# set_cookie('k',123)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
- 引擎的配置
详见别人博客
- 扩展:Session用户验证
def login(func):
def wrap(request, *args, **kwargs):
# 如果未登陆,跳转到指定页面
if request.path == '/test/':
return redirect('http://www.baidu.com')
return func(request, *args, **kwargs)
return wrap
- session用户登陆及CSRF相关示例
# urls.py
url(r'^login/$', views.login),
url(r'^index/', views.index),
url(r'^logout/', views.logout),
# views.py
from django.shortcuts import render,redirect,HttpResponse
# Create your views here.
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':
# 生成随机字符串,写到用户cookie,保存到session
# 随机字符串中 设置相关内容
# makemigrations, migrate
request.session['username'] = user
request.session['is_login'] = True
if request.POST.get('rmb')=='1':
request.session.set_expiry(10)
return redirect('/index/')
else:
return render(request,'login.html')
# from django.views.decorators.csrf import csrf_exempt,csrf_protect
# @csrf_exempt
# @csrf_protect
# 局部设置
def index(request):
# 获取当前用户字符串,并获取对应信息
if request.session.get('is_login',None):
return render(request,'index.html')
else:
return HttpResponse('go back')
# index.html
def logout(request):
request.session.clear()
return redirect('/login/')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>welcome:{{ request.session.username }}</h1>
<a href="/logout/">leave</a>
</body>
</html>
# login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="/login/"method="POST">
{% csrf_token %}
<input type="text" name="user">
<input type="text" name="pwd">
<input type="checkbox"name="rmb"value="1">10秒免登陆
<input type="submit">
<input id="btn" type="button"value="A提交">
<script src="/static/jquery-1.12.4.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
$(function () {
$.ajaxSetup({
// 全局配置,对所有ajax配置请求头,携带csrf-token
beforeSend:function (xhr,settings) {
xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
}
});
{# var csrf_tonken = $.cookie('csrftoken');#}
// get等请求时不携带x-csrftoken,需要在此做出判断,具体见其他。
$('#btn').click(function () {
$.ajax({
url:'/login/',
type:'POST',
{# headers:{'X-CSRFtoken': $.cookie('csrftoken')},#}
data:{'user':'root','pwd':'123'},
success: function (arg) {
}
})
});
})
</script>
</form>
</body>
</html>
- CSRF
a. CSRF原理
b. 无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
c. Form提交(CSRF)
d. Ajax提交(CSRF)
CSRF请求头 X-CSRFToken
- 应用
1、普通表单
veiw中设置返回值:
return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))
或者
return render(request, 'xxx.html', data)
html中设置Token:
{% csrf_token %}
2、Ajax
# 对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。
view.py
from django.template.context import RequestContext
# Create your views here.
def test(request):
if request.method == 'POST':
print request.POST
return HttpResponse('ok')
return render_to_response('app01/test.html',context_instance=RequestContext(request))
text.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
{% csrf_token %}
<input type="button" onclick="Do();" value="Do it"/>
<script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
<script src="/static/plugin/jquery/jquery.cookie.js"></script>
<script type="text/javascript">
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 Do(){
$.ajax({
url:"/app01/test/",
data:{id:1},
type:'POST',
success:function(data){
console.log(data);
}
});
}
</script>
</body>
</html>
3、更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。