CSIC_716_20200114【Django入门---django中间件、csrf跨站请求伪造、auth认证】
中间件
凡是全局相关的功能,都可以考虑使用中间件来实现。例如:全局的身份校验、访问频率校验、访问黑名单、访问白名单。
中间件总共有5个方法可以使用:
process_request
请求从web服务网关接口传到中间件层时,会按照先后顺序依次执行每一个中间件里的process_request方法,遇到没有process_request的中间件会直接跳到下一个中间件。如果不满足其中任何一个就会被拒绝访问。如果process_request返回了一个值HttpResponse对象,那么程序就会从此原路返回,返回的路线要么经过process_response,如果没有process_response也能直接通过HttpResponse返回到前端。
process_response
当执行完视图函数后,程序会按照与process_request相反的顺序执行process_response方法。
该方法必须要有return返回值,否则报错。一般是return response,也可以自己返回一个HttpResponse替换从视图函数传过来的值,外层可以偷换内层传出来的东西
process_view
在中间件放行后,执行视图函数之前,会执行process_view
process_template_response
他在视图函数执行完之后,process_response执行前执行,他的执行顺序和process_response一样,顺序反向。他触发的条件是:视图函数返回的对象中必须要有render属性对应的render方法。
process_exception
在视图函数报错的时候触发,顺序也是反向的。
上面五个方法的执行顺序:
csrf
form表单如何通过csrf校验
你只需要在你的form表单内写一个
{% csrf_token %}
ajax如何通过csrf校验
// 第一种方式 自己手动获取 {#data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},#} // 第二种方式 利用模板语法 {#data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#} // 第三种 通用方式 引入外部js文件 官网提供的方式 {% load static %} <script src="{% static 'myset.js' %}"></script> data:{'username':'jason'}
其中导入Ajax跨站请求伪造的js文件为
1 function getCookie(name) { 2 var cookieValue = null; 3 if (document.cookie && document.cookie !== '') { 4 var cookies = document.cookie.split(';'); 5 for (var i = 0; i < cookies.length; i++) { 6 var cookie = jQuery.trim(cookies[i]); 7 // Does this cookie string begin with the name we want? 8 if (cookie.substring(0, name.length + 1) === (name + '=')) { 9 cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 10 break; 11 } 12 } 13 } 14 return cookieValue; 15 } 16 var csrftoken = getCookie('csrftoken'); 17 function csrfSafeMethod(method) { 18 // these HTTP methods do not require CSRF protection 19 return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 20 } 21 22 $.ajaxSetup({ 23 beforeSend: function (xhr, settings) { 24 if (!csrfSafeMethod(settings.type) && !this.crossDomain) { 25 xhr.setRequestHeader("X-CSRFToken", csrftoken); 26 } 27 } 28 });
csrf相关装饰器 当我们网站整体都校验csrf的时候 我想让某几个视图函数不校验 当我们网站整体都不校验csrf的时候 我想让某几个视图函数校验 from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views import View9 from django.utils.decorators import method_decorator # @method_decorator(csrf_protect,name='post') # 第二种指名道姓的给类中某个方法装 # @method_decorator(csrf_exempt,name='post') # csrf_exempt 第二种方式不行 @method_decorator(csrf_exempt,name='dispatch') # 可以!!! class MyHome(View): # APIView # @method_decorator(csrf_protect) # 第三种 类中所有的方法都装 # @method_decorator(csrf_exempt) # csrf_exempt 第三种方式可以 def dispatch(self, request, *args, **kwargs): return super().dispatch(request,*args,**kwargs) def get(self,request): return HttpResponse('get') # @method_decorator(csrf_protect) # 第一种方式 # @method_decorator(csrf_exempt) # csrf_exempt 第一种方式不行 def post(self,request): return HttpResponse('post')
"""
给CBV加装饰器 推荐你使用模块method_decorator
我们自己写的装饰器和csrf_protect用法一致
唯独csrf_exempt是一个特例 只能给dispatch方法装
"""
auth模块
django用户相关的自带的功能模块 auth_user表
如何创建超级用户
createsuperuser
模块导入
from django.contrib import auth
from django.contrib.auth.models import User
auth方法大全
1.创建用户 User.objects.create() # 密码是明文 User.objects.createuser() # 基本都用它 User.objects.createsuperuser() # 邮箱要给数据 2.校验用户名和密码是否正确 auth.authenticate(username=username,password=password) # 用户名和密码两个一个都不能少 # 该方法当用户名和密码正确的时候返回的用户对象 不正确返回None 3.保存用户登录状态 auth.login(request,user_obj) # 这一句执行之后 request.user获取当前登录的用户对象 4.如何判断当前用户是否登录 以及如何获取当前登录用户对象 request.user.is_authenticated() # 判断是否登录 request.user # 登录用户对象 5.校验用户是否登录 from django.contrib.auth.decorators import login_required # 局部配置 @login_required(login_url='/login/') def xxx(request): return HttpResponse('xxx页面') # 全局配置 配置文件中写以下代码 LOGIN_URL = '/login/' @login_required def xxx(request): return HttpResponse('xxx页面') # 如果两个都设置了 那么优先执行局部配置 6.修改密码 request.user.check_password(old_password) # 校验原密码是否正确 request.user.set_password(new_password) request.user.save() # 一定要保存 7.注销功能 auth.logout(request)
from django.contrib import auth from django.contrib.auth.models import User def register(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # User.objects.create(username=username,password=password) # 不能使用 密码变成明文的了 # User.objects.create_user(username=username,password=password) # 不能使用 密码变成明文的了 # User.objects.create_superuser(username=username,password=password,email='123@qq.com') # 不能使用 密码变成明文的了 return render(request,'register.html') def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # 明文 # 数据库校验用户名和密码是否正确 # User.objects.filter(username=username,password=password) user_obj = auth.authenticate(request,username=username,password=password) """ 用户名密码正确返回的是用户对象 错误返回None """ # print(res) # print(res.username) # print(res.password) if user_obj: # 保存用户登录状态 # request.session auth.login(request,user_obj) """ 只要执行了这一句话 之后在任意可以获取到request对象的地方 都可以通过request.user获取到当前登录的用户对象 """ return HttpResponse("登录成功") return render(request,'login.html') def get_user(request): print(request.user) """ 用户登录成功之后 request.user拿到的就是用户对象 没有登录 获取到的匿名用户 """ print(request.user.is_authenticated()) return HttpResponse("get_user") # 校验用户是否登录装饰器 from django.contrib.auth.decorators import login_required # @login_required(login_url='/login/') @login_required def xxx(request): return HttpResponse('xxx页面') # @login_required(login_url='/login/') # @login_required @login_required(login_url='/jskahdhsajhdjsadhjk/') def yyy(request): return HttpResponse('yyy页面') # @login_required(login_url='/login/') @login_required def zzz(request): return HttpResponse('zzz页面') @login_required def set_password(request): if request.method == 'POST': old_password = request.POST.get('old_password') new_password = request.POST.get('new_password') # 1 先校验旧密码是否正确 is_right = request.user.check_password(old_password) # print(is_right) # 2 再去修改新密码 if is_right: request.user.set_password(new_password) request.user.save() # 一定要save一下 否则无影响 return render(request,'set_password.html') @login_required def logout(request): auth.logout(request) return HttpResponse('注销成功')
如何扩展auth_user表
# 1 利用一对一表关系()
# 2 利用类的继承
# 1 类的继承
from django.contrib.auth.models import User,AbstractUser # Create your models here. class Userinfo(AbstractUser): phone = models.BigIntegerField() avatar = models.FileField() # 扩展的字段 尽量不要与原先表中的字段冲突
# 2 配置文件
AUTH_USER_MODEL = '应用名.表名'
"""
django就会将userinfo表来替换auth_user表
并且之前auth模块所有的功能不变 参照的也是userinfo表
"""
顶