python middles_[Python自学] day-22 (1) (Session、CSRF、中间件)

一、响应函数补充

三种返回响应的方式:

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()

}

})

})

})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值