Django的cookie、session和中间件的自定义使用和importlib模块的使用

一、cookie session token简单介绍

1 https://www.cnblogs.com/liuqingzheng/articles/8990027.htmlp
    
2 cookie:客户端浏览器上的键值对
3 session:存在服务端的键值对
4 token:加密的键值对,如果放在客户端浏览器上,它就叫cookie,  服务端签发的加密字符串

head.{name:wuxi,age:18}.eseetsweasdca

base64加码:

asdfasfd.asdfasdf.asdfasdfaeraew

后端校验:
用这个token去查我的账户余额,向银行发请求,银行校验通过,是银行给你的,---》返回你的余额
head.{name:wuxi,age:18}.eseetsweasdca

head.{name:wen,age:18}.eseetsweasdca

二、django中cookie的使用

def cookie_test(request):
    # 浏览器向我这个地址发一个请求,就在浏览器写入 name = wuxi

    obj=HttpResponse('ok')
    obj.set_cookie('name','wuxi')  # 写入到浏览器了,在http响应头里:cookie: name=wen
    obj.set_cookie('age','19')  
    return obj


def get_cookie(request):

    print(request.COOKIES)
    print(request.COOKIES.get('name'))
    return HttpResponse('我拿了你传过来的cookie')


def delete_cookie(request):
    obj=HttpResponse('我删掉了你 name 这个cookie ')
    obj.delete_cookie('name')
    return obj
#  带签名的cookie(加盐,加密)
	-增:obj.set_signed_cookie('name','wuxi','123')
    -: obj.delete_cookie('name')  # 设置过期
    -: request.get_signed_cookie('name',salt='123')
    -: obj.set_signed_cookie('name','wuxi2','123')

三、django中session的使用和配置

1 存在于服务端的键值对

2 同一个浏览器不允许登录多个账户,不同浏览器可以登录同一个账户

3 session的使用(必须迁移数据),当做字典来处理
	-增:request.session['name']='wuxi'
    -查:request.session['name']
    -改:request.session['name']='WUXI'
    -删:del request.session['name']
    -设置过期时间:request.session.set_expiry(10)


request.session.set_expiry()
	1.数字								秒数
    2.datetime.timedelta(days=3)格式				日期格式
    3.None								  参加全局失效策略
    4.0									  窗口关闭即失效
    

4 session的其它使用
	-request.session.setdefault('k1',123)
    -request.session.get('name',None)
    -del request.session['k1']
    
    -request.session.keys()
	-request.session.values()
    -request.session.items()
    -request.session.session_key # 获取那个随机字符串,django_session表中session_key字段
	
    -request.session.clear_expired() # 清除django_session表中,过期的session
    -request.session.exists("session_key") # 判断这个随机字符串(session_key字段),有没有数据
    -request.session.delete() # 删除所有的值,django_session表中删除当前登录者的这条记录
    -request.session.flush()  # 干了上面那个事,把cookie设置为过期

def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
                   domain=None, secure=False, httponly=False)

# key
# value
# max_age:传个数字,以秒计,过期时间,有默认值 (6天后过期:60*60*24*5)
---了解
# expires:传时间对象,date=datetime.timedelta(days=5)  5天后过期
# path:默认 / 表示当前域下的所有路径  http://127.0.0.1:8000/wuxi/dfd/
# domain:在那个域下有效
# secure:是否Https传输cookie
# httponly:cookie只支持http传输

1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)

2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 

4. 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎

5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎

其他公用设置项:
SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)***记住

---了解
SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)

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_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)

四、cbv加装饰器

from django.views import View
from django.utils.decorators import method_decorator
# 使用登录认证装饰器
# 用法一

@method_decorator(login_auth,name='get')
@method_decorator(login_auth,name='post')
class UserInfo(View):
    # 用法二
    @method_decorator(login_auth)
    def get(self, request, *args, **kwargs):
        return HttpResponse('userinfo get')
    
    # 用法三
    @methed_decorator(login_auth)
    def dispatch(self,request, *args, **kwargs):
        return super(UserInfo, self).dispatch(request, *args, **kwargs)
    
# 总结:三种用法
	-加在类上:@method_decorator(login_auth,name='get')
    -加在方法上:@method_decorator(login_auth)
	-加在dispatch方法上,以下所有的类都会装饰上

五、自定义中间件

1 自定义步骤:
	-写一个类,继承MiddlewareMixin
    -里面写方法process_request(请求来了,一定会触发它的执行)
    -在setting中配置(注意,放在前和放在后)
    	MIDDLEWARE = [
            ...
    		'app01.mymiddle.MyMiddleware1',
            ...
		]


1 process_request(self, request对象)
2 process_response(self, request对象, response对象)
3 多个中间件,执行顺序是什么?
	# 请求来的时候从上往下执行:process_request
    
    # 请求走的时候,从下往上执行:process_response
        
        
4 process_request可以干什么?
	-写一个中间件,不管前端用什么编码,在requset.data中都有post的数据
    -频率限制(限制某个ip地址,一分钟只能访问5次)
    -登录认证(只要没登录,重定向到login路径)、
    -记录用户访问日志(ip,时间,访问路径)
    -可以return值,但当前请求会直接返回
    
5 process_response可以干什么?内部有response对象
	-统一给所有(某几个路径)加cookie
    -统一给所有(某几个路径)加响应头
    

 """
 		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方法   
 """   


    
6 process_view 路由匹配成功和视图函数执行之前执行(callback就是视图函数),顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
    def process_view(self, request, callback, callback_args, callback_kwargs):
            # print(callback)
            # print(callback_args)
            # print(callback_kwargs)
            #
            res=callback(request)  # 提前调用视图函数
            #
            print("中间件1的process_view")
            return res
7 process_exception 视图函数出错,会执行它(全局异常捕获)(记录日志,哪个ip地址,访问哪个路径,出的错)
    # 全局异常捕获,返回4开头的
    def process_exception(self, request, exception):
        print(exception)
        return render(request,'error.html')


8 process_template_response
			返回的HttpResponse对象有render属性的时候才会触发
			顺序是按照配置文件中注册了的中间件从下往上依次经过

六、CSRF_TOKEN跨站请求伪造

1 跨站请求伪造
2 代码演示


3 django解决了csrf攻击,中间件:django.middleware.csrf.CsrfViewMiddleware


4 后期中间件不能注释,每次发送post请求,都需要携带csrf_token随机字符串
	-form表单提交 
    	-在form表单中 {% csrf_token %}
        
    -ajax提交(如何携带)
    方式一:放到data中
     $.ajax({
            url: '/csrf_test/',
            method: 'post',
            data: {'name': $('[name="name"]').val(),
                'password': $('[name="password"]').val(),
                'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()
            },
            success: function (data) {
                console.log('成功了')
                console.log(data)

            },
            error: function (data) {
                console.log('xxxxx')
                console.log(data)

            }
        })
        方式二:放到data中
        'csrfmiddlewaretoken':'{{ csrf_token }}'
        方式三:放到头中
        	headers:{'X-CSRFToken':'{{csrf_token}}'},
        
        
 # jquery.cookie.js
	-在浏览器中对cookie进行增,删,查,改
    -前后端分离(js操作cookie)
    
// 第三种 通用方式直接拷贝js代码并应用到自己的html页面上即可

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]);
            // Does this cookie string begin with the name we want?
            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) {
  // 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);
    }
  }
});
    
    
# 全局使用,局部禁csrf
	-在视图函数上加装饰器
    from django.views.decorators.csrf import csrf_exempt,csrf_protect
# 全局启用,局部禁用(中间件不能注释,这个视图函数,已经没有csrf校验了)
 @csrf_exempt
 def csrf_test(request):
     if request.method=='GET':
         return render(request,'csrf_test.html')
     else:
         name=request.POST.get('name')
         password=request.POST.get('password')
         print(name)
         print(password)
         return HttpResponse('登录成功')

# 全局禁用,局部使用csrf
@csrf_protect
def csrf_test(request):
    if request.method=='GET':
        return render(request,'csrf_test.html')
    else:
        name=request.POST.get('name')
        password=request.POST.get('password')
        print(name)
        print(password)
        return HttpResponse('登录成功')



# 古怪的使用方式,在urls.py中
path('csrf_test/', csrf_exempt(views.csrf_test))




from django.views import View

# @method_decorator(csrf_protect,name='post')  # 针对csrf_protect 第二种方式可以
# @method_decorator(csrf_exempt,name='post')  # 针对csrf_exempt 第二种方式不可以
@method_decorator(csrf_exempt,name='dispatch')
class MyCsrfToken(View):
    # @method_decorator(csrf_protect)  # 针对csrf_protect 第三种方式可以
    # @method_decorator(csrf_exempt)  # 针对csrf_exempt 第三种方式可以
    def dispatch(self, request, *args, **kwargs):
        return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)

    def get(self,request):
        return HttpResponse('get')

    # @method_decorator(csrf_protect)  # 针对csrf_protect 第一种方式可以
    # @method_decorator(csrf_exempt)  # 针对csrf_exempt 第一种方式不可以
    def post(self,request):
        return HttpResponse('post')

七、importlib模块

# 模块:importlib
import importlib
res = 'myfile.b'
ret = importlib.import_module(res)  # from myfile import b
# 该方法最小只能到py文件名
print(ret)




import settings  # 自定义的配置文件,里面配置的是字符串
import importlib


def send_all(content):
    for path_str in settings.NOTIFY_LIST:  #'notify.email.Email'
        module_path,class_name = path_str.rsplit('.',maxsplit=1)
        # module_path = 'notify.email'  class_name = 'Email'
        # 1 利用字符串导入模块
        module = importlib.import_module(module_path)  # from notify import email
        # 2 利用反射获取类名
        cls = getattr(module,class_name)  # Email、QQ、Wechat
        # 3 生成类的对象
        obj = cls()
        # 4 利用鸭子类型直接调用send方法
        obj.send(content)

你可能感兴趣的:(后端之Django,Django,python,django)