一、响应函数补充
三种返回响应的方式:
returnHttpResponse()returnrender()return redirect()
HttpResponse:
除了能够返回字符串,还能返回bytes。
content = "Hello"
returnHttpResponse(content)return HttpResponse(bytes(content))
render:
返回渲染后的模板。
return render(request, 'mlogin.html', {"pwd_error": pwd_error_msg})
redirect:
跳转到url。
return redirect('/mgmt/host')
三种方式都可以设置cookie:
response = redirect(...) #或HttpResponse、render
response.set_cookie('key', 'value')
set_cookie是将cookie放在响应头中的。
二、Session介绍
由于Cookie存放在客户端浏览器,所以Cookie是不安全的,可以被人查看和修改,甚至伪造。
Cookie不适合存放敏感信息,例如密码等。
所以,我们可以将原本存放在Cookie中的数据,放置到服务器端,例如:
{'username':'Alex','id':'12973','favor':'xxxxxx'}
然后,服务器在保存这些数据之前,生成一个随机字符串。并将这个字符串使用set_cookie放置在客户端。并在服务器也保存一份,作为数据的key,例如:
session ={#某用户的session
'h9j2j3987d2bksjf98': {'username': 'Alex','id': '12973','is_login':True,'favor': 'xxxxxx'},#另一个用户的session
'h978hnjdfi9100':{'username': 'Leo','id': '12989','is_login':True,'favor': 'yyyyyy'}
}
客户端浏览器保存的cookie为:
sessionid = 'h9j2j3987d2bksjf98'
当用户请求时,携带该sessionid。服务器拿到这个随机ID后,会到session中查到对应的数据(例如is_login),如果is_login为True,则说明用户登录过。
优点:同样完成了用户验证,而且数据存放在服务端,安全性更高。
缺点:增加了服务器开销。
三、Session使用
1.使用Session前创建数据库
python manage.py makemigrations
python manage.py migrate
2.查看session表
Django的Session默认是放在数据库的django_session表中的。
3.在视图函数中使用session
deflogin(request):#如果是get请求,则检查session中is_login是否为True,如果有则免登录,没有则跳转到登录界面
if request.method == 'GET':if request.session.get('is_login'):return redirect('/index')else:return render(request, 'login.html')#如果是post请求,则获取请求数据,并验证用户名密码。
if request.method == 'POST':
user= request.POST.get('user')
pwd= request.POST.get('pwd')#如果验证通过,则写session,写入username和is_login,并跳转到业务页面index
if user == USER_DICT.get('username') and pwd == USER_DICT.get('password'):
request.session['username'] =user
request.session['is_login'] =Truereturn redirect('/index')else:#没验证通过,则跳转回login页面
return redirect('/login')
4.django处理session原理
1)当我们使用request.session['is_login']=True设置session时,django会自动生成随机字符串(set_cookie以及自己保留一份存数据库)
2)存放session的键值对到数据库中(现在很多可能使用的是NOSQL数据库,例如redis之类,并且session要提供共享功能,方便网站分布式部署)
3)当浏览器带着sessionid请求时(如下图),视图函数中使用request.session['is_login']获取值时,django会使用sessionid,去数据库中查询对应条目的is_login(如下图)
很多网站不一定使用Django框架,所以在请求头中不一定能看到sessionid,但一般都有一个对应的ID来表示用户:
这是博客园存放的已登录用户的随机字符串,类似于sessionid。后台拿到这个id后,可以从数据库中获取用户信息。
四、session操作
Django为session提供了很多操作。
1.普通键值操作
#类似字典操作session
request.session['k1'] = 123 #设置k1的值
k1 = request.session['k1'] #取k1的值,如果k1不存在,则报错
k1 = request.session.get('k1', None) #取k1的值,不存在则返回None
del request.session['k1'] #删除k1及对应的值
2.键值批量操作
request.session.keys() #获取所有key列表
request.session.values() #获取所有value
request.session.items() #获取所有键值对
request.session.iterkeys() #返回所有key迭代器
request.session.itervalues() #返回所有value迭代器
request.session.iteritems() #返回所有item迭代器
3.session删除操作
#清空数据库中过期的session
request.session.clear_expired()#获取用户对应随机字符串(cookie中的sessionid)
sk =request.session.session_key#判断随机字符串在数据库是否存在(一般用不到,因为在获取session某个值得时候底层也会进行这个操作)
request.session.exists(sk)#删除当前用户的所有Session数据
request.session.delete(sk)#或
request.session.clear() #一般在用户注销时使用
4.session过期时间
为session设置过期时间:
request.session.set_expiry(10) #单位是秒
当这样设置以后,所有session的过期时间都是10秒。如果不设置的话,Session的过期时间默认是两周。
设置浏览器关闭时过期:
request.session.set_expiry(0) #设置为0时,浏览器关闭过期
在这种情况下,浏览器的sessionid cookie没有设置过期时间,所以关闭浏览器,Cookie就消失了, 自然无法再利用session来认证。但是在后台数据库中还存在sessionid的记录。
五、session配置
1.Session默认配置:
先查看一下Django对Session的默认配置:
from django.conf importsettingsprint(settings.SESSION_COOKIE_NAME) #'sessionid'
print(settings.SESSION_COOKIE_PATH) #'/'
print(settings.SESSION_COOKIE_DOMAIN) #None
print(settings.SESSION_COOKIE_SECURE) #False
print(settings.SESSION_COOKIE_HTTPONLY) #True
print(settings.SESSION_COOKIE_AGE) #1209600
print(settings.SESSION_EXPIRE_AT_BROWSER_CLOSE) #False
print(settings.SESSION_SAVE_EVERY_REQUEST) #False
以上打印的值即为默认值。
要修改session的默认配置,只需在settings.py配置文件中修改:
SESSION_COOKIE_NAME = "sessionid" #session产生的随机字符串保存到浏览器cookie时的名字,默认就是sessionid
SESSION_COOKIE_PATH = "/" #Session的cookie生效路径
SESSION_COOKIE_DOMAIN = None #Session的cookie生效域名
SESSION_COOKIE_SECURE = False #是否Https传输cookie
SESSION_COOKIE_HTTPONLY = True #是否只支持http传输
SESSION_COOKIE_AGE = 1209600 #默认两周失效
SESSION_EXPIRE_AT_BROWSER_CLOSE = False #是否关闭浏览器使得Session过期
SESSION_SAVE_EVERY_REQUEST = False #是否每次请求都保存Session,即失效时间根据每次请求向后推
以上配置直接写在setting中即可。
2.Session配置后端存储
数据库后端:(默认)
# settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.db' #引擎(默认)
缓存后端:
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'SESSION_CACHE_ALIAS= 'default'CACHES={'default': {'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache','LOCATION': ['192.168.1.3:11211','192.168.1.4:11211',
]
},
}
文件后端:
SESSION_ENGINE = 'django.contrib.sessions.backends.file' #引擎
#SESSION_FILE_PATH = None #缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()SESSION_FILE_PATH = os.path.join(BASE_DIR,'cache') # 在工程目录下创建一个cache目录来存放session
缓存+数据库作为后端:(推荐)
数据库做持久化,缓存提高效率。前提是缓存和数据库都要配置好,参照前面分别的配置。
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
加密cookie session:(不推荐)
将session的数据全部加密后放在cookie中,这种方式不能算一种后端存储技术,实际上都是cookie了。
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
总结:以上几种Session配置只是使用的引擎不同,使用方法都是一样的。前面的默认配置就是通用配置。
Redis作为Session存储(推荐):
第一种配置方法:
首先安装django-redis-sessions:
pip install django-redis-sessions
# settings中配置
SESSION_ENGINE= 'redis_sessions.session'SESSION_REDIS={'host': '192.168.1.181','port': 6379,'db': 2, # 哪个数据库'password': '','prefix': 'session', # key的前缀'socket_timeout': 10}
可以看到在redis中,session存储为以下形式:
127.0.0.1:6379[2]> keys *
1) "session:fnifus1tqkbilhr1k549mcn5q9k5utdv"
形式为,prefix:session_id。
第二种配置方法:
首先安装django_redis:
pip install django_redis
#在settings中配置
CACHES ={"default": {"BACKEND": "django_redis.cache.RedisCache",#把这里缓存你的redis服务器ip和port
"LOCATION": "redis://192.168.1.181:6379/3","OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}#我们定义一个cache(本地缓存来存储信息,cahe指定的是redis
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
#指定本地的session使用的本地缓存名称是'default'
SESSION_CACHE_ALIAS = "default"
这种配置方式下,session存储为以下形式:
127.0.0.1:6379[3]> keys *
1) ":1:django.contrib.sessions.cachefj33bv40gk7gf2srklfi2fminmohnskb"
六、CSRF
在前面的章节,我们注释掉了CSRF中间件,因为发送post请求的时候出现403错误。
1.CSRF原理
CSRF是用来防止有人在其他非法站点向我们的某个页面发送POST请求。
CSRF启用的时候,我们以GET方式请求一个页面时,Django会生成随机字符串(分别放在render的参数中,以及cookie中,两个字符串是独立的),并传递到页面。
在我们提交表单时,必须携带该随机字符串,才能正常提交,否则报403forbid错误。
由于我们提交数据可以使用form表单,也可以使用Ajax,所以对应两个地方需要获取随机字符串。
在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',
]
2.Form表单提交时使用CSRF
{% csrf_token %}
我们使用了{%csrf_token%}后,在页面元素中可以看到:
Django为我们自动添加了一个隐藏的标签,value就是csrf随机字符串。后台可以自动获取这个值并验证。
3.在Ajax提交Post请求时使用CSRF
Login{% csrf_token %}
$('#ajax_btn').click(function(){
$.ajax({
url:'/login',
type:'POST',
data:{'user':'leokale','pwd':123},
headers:{'X-CSRFtoken':$.cookie('csrftoken')},
success:function(arg){
location.reload()
}
})
})
})