django中间件
"""
django中间件是django的门户
1.请求来的时候需要先经过中间件才能到达真正的django后端
2.响应走的时候最后也需要经过中间件才能发送出去
django自带七个中间件
"""
django请求生命周期流程图
研究django中间件代码规律
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' ,
]
class SessionMiddleware ( MiddlewareMixin) :
def process_request ( self, request) :
session_key = request. COOKIES. get( settings. SESSION_COOKIE_NAME)
request. session = self. SessionStore( session_key)
def process_response ( self, request, response) :
return response
class CsrfViewMiddleware ( MiddlewareMixin) :
def process_request ( self, request) :
csrf_token = self. _get_token( request)
if csrf_token is not None :
request. META[ 'CSRF_COOKIE' ] = csrf_token
def process_view ( self, request, callback, callback_args, callback_kwargs) :
return self. _accept( request)
def process_response ( self, request, response) :
return response
class AuthenticationMiddleware ( MiddlewareMixin) :
def process_request ( self, request) :
request. user = SimpleLazyObject( lambda : get_user( request) )
"""
django支持自定义中间件并且暴露给程序员五个可以自定义的方法
process_request
process_response
process_view
process_template_response
process_exception
"""
如何自定义中间件
"""
1.在项目名或者应用名下创建一个任意名称的文件夹
2.在该文件夹内创建一个任意名称的py文件
3.在该py文件内需要书写类(这个类必须继承MiddlewareMixin)
然后在这个类里面就可以自定义五个方法了
(这五个方法并不是全部都需要书写,用几个写几个)
4.需要将类的路径以字符串的形式注册到配置文件中才能生效
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',
'你自己写的中间件的路径1',
'你自己写的中间件的路径2',
'你自己写的中间件的路径3',
]
"""
"""
1.必须掌握
process_request
1.请求来的时候需要经过每一个中间件里面的process_request方法
结果的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
2.如果中间件里面没有定义该方法,那么直接跳过执行下一个中间件
3.如果该方法返回了HttpResponse对象,那么请求将不再继续往后执行
而是直接原路返回(校验失败不允许访问...)
process_request方法就是用来做全局相关的所有限制功能
process_response
1.响应走的时候需要结果每一个中间件里面的process_response方法
该方法有两个额外的参数request,response
2.该方法必须返回一个HttpResponse对象
1.默认返回的就是形参response
2.你也可以自己返回自己的
3.顺序是按照配置文件中注册了的中间件从下往上依次经过
如果你没有定义的话 直接跳过执行下一个
研究如果在第一个process_request方法就已经返回了HttpResponse对象,那么响应走的时候是经过所有的中间件里面的process_response还是有其他情况
是其他情况
就是会直接走同级别的process_reponse返回
flask框架也有一个中间件但是它的规律
只要返回数据了就必须经过所有中间件里面的类似于process_reponse方法
2.了解即可
process_view
路由匹配成功之后执行视图函数之前,会自动执行中间件里面的该放法
顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
process_template_response
返回的HttpResponse对象有render属性的时候才会触发
顺序是按照配置文件中注册了的中间件从下往上依次经过
process_exception
当视图函数中出现异常的情况下触发
顺序是按照配置文件中注册了的中间件从下往上依次经过
"""
CBV添加装饰器
def login_auth ( func) :
def inner ( request, * args, ** kwargs) :
if request. COOKIES. get( 'username' ) :
return func( )
else :
return redirect( '/login/' )
return inner
from django. views import View
from django. utils. decorators import method_decorator
class IndexView ( View) :
@method_decorator ( login_auth)
def dispatch ( self, request, * args, ** kwargs) :
pass
def get ( self, request) :
return HttpResponse( 'get' )
def post ( self, request) :
return HttpResponse( 'post' )
csrf跨站请求伪造
"""
钓鱼网站
我搭建一个跟正规网站一模一样的界面(中国银行)
用户不小心进入到了我们的网站,用户给某个人打钱
打钱的操作确确实实是提交给了中国银行的系统,用户的钱也确确实实减少了
但是唯一不同的时候打钱的账户不适用户想要打的账户变成了一个莫名其妙的账户
大学英语四六级
考之前需要学生自己网站登陆缴费
内部本质
我们在钓鱼网站的页面 针对对方账户 只给用户提供一个没有name属性的普通input框
然后我们在内部隐藏一个已经写好name和value的input框
如何规避上述问题
csrf跨站请求伪造校验
网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
当这个页面朝后端发送post请求的时候 我的后端会先校验唯一标识,如果唯一标识不对直接拒绝(403 forbbiden)如果成功则正常执行
"""
如何符合校验
< form action= "" method= "post" >
{ % csrf_token % }
< 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>
// 第一种 利用标签查找获取页面上的随机字符串
{
// 第二种 利用模版语法提供的快捷书写
{
// 第三种 通用方式直接拷贝js代码并应用到自己的html页面上即可
data: { "username" : 'jason' }
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] ) ;
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 ) {
return ( / ^(GET|HEAD|OPTIONS|TRACE)$ / . test ( method) ) ;
}
$. ajaxSetup ( {
beforeSend : function ( xhr, settings ) {
if ( ! csrfSafeMethod ( settings. type) && ! this . crossDomain) {
xhr. setRequestHeader ( "X-CSRFToken" , csrftoken) ;
}
}
} ) ;
csrf相关装饰器
"""
1.网站整体都不校验csrf,就单单几个视图函数需要校验
2.网站整体都校验csrf,就单单几个视图函数不校验
"""
from django. views. decorators. csrf import csrf_protect, csrf_exempt
from django. utils. decorators import method_decorator
"""
csrf_protect 需要校验
针对csrf_protect符合我们之前所学的装饰器的三种玩法
csrf_exempt 忽视校验
针对csrf_exempt只能给dispatch方法加才有效
"""
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' )
from django. views import View
@method_decorator ( csrf_exempt, name= 'dispatch' )
class MyCsrfToken ( View) :
def dispatch ( self, request, * args, ** kwargs) :
return super ( MyCsrfToken, self) . dispatch( request, * args, ** kwargs)
def get ( self, request) :
return HttpResponse( 'get' )
def post ( self, request) :
return HttpResponse( 'post' )
补充知识点
import importlib
res = 'myfile.b'
ret = importlib. import_module( res)
print ( ret)
重要思想
import settings
import importlib
def send_all ( content) :
for path_str in settings. NOTIFY_LIST:
module_path, class_name = path_str. rsplit( '.' , maxsplit= 1 )
module = importlib. import_module( module_path)
cls = getattr ( module, class_name)
obj = cls( )
obj. send( content)
Auth模块
"""
其实我们在创建好一个django项目之后直接执行数据库迁移命令会自动生成很多表,这些表里面有auth开头的,django开头的
django_session
auth_user
django在启动之后就可以直接访问admin路由,需要输入用户名和密码,数据参考的就是auth_user表,并且还必须是管理员用户才能进入
创建超级用户(管理员)
python3 manage.py createsuperuser
依赖于auth_user表完成用户相关的所有功能
"""
方法总结
user_obj = auth. authenticate( request, username= username, password= password)
print ( user_obj)
print ( user_obj. username)
print ( user_obj. password)
auth. login( request, user_obj)
request. user. is_authenticated( )
request. user
from django. contrib. auth. decorators import login_required
@login_required ( login_url= '/login/' )
LOGIN_URL = '/login/'
1 . 如果局部和全局都有 该听谁的?
局部 > 全局
2 . 局部和全局哪个好呢?
全局的好处在于无需重复写代码 但是跳转的页面却很单一
局部的好处在于不同的视图函数在用户没有登陆的情况下可以跳转到不同的页面
request. user. check_password( old_password)
request. user. set_password( new_password)
request. user. save( )
auth. logout( request)
from django. contrib. auth. models import User
User. objects. create( username= username, password= password)
User. objects. create_user( username= username, password= password)
User. objects. create_superuser( username= username, email= '123@qq.com' , password= password)
如何扩展auth_user表
from django. db import models
from django. contrib. auth. models import User, AbstractUser
class UserInfo ( AbstractUser) :
"""
如果继承了AbstractUser
那么在执行数据库迁移命令的时候auth_user表就不会再创建出来了
而UserInfo表中会出现auth_user所有的字段外加自己扩展的字段
这么做的好处在于你能够直接点击你自己的表更加快速的完成操作及扩展
前提:
1.在继承之前没有执行过数据库迁移命令
auth_user没有被创建,如果当前库已经创建了那么你就重新换一个库
2.继承的类里面不要覆盖AbstractUser里面的字段名
表里面有的字段都不要动,只扩展额外字段即可
3.需要在配置文件中告诉django你要用UserInfo替代auth_user(******)
AUTH_USER_MODEL = 'app01.UserInfo'
'应用名.表名'
"""
phone = models. BigIntegerField( )
"""
你如果自己写表替代了auth_user那么
auth模块的功能还是照常使用,参考的表页由原来的auth_user变成了UserInfo
"""