csrf 跨站请求
1'''
2csrf跨站请求伪造,就相当于一个钓鱼网站
3'''
4eg:我搭建了一个跟正规银行网站一模一样的界面
5用户不小心进入到了我们的网站,用户给某个人打钱
6打钱的操作确实是提交到了银行的系统,用户的钱也确实减少了,但是唯一不同的是打钱的账户并不是用于想要转钱的账户
7
8内部本质
9 我们在钓鱼网站的页面,针对对方账户,只给用户提供一个没有name属性的普通input框,然后我们在内部隐藏一个已经写好的name和value的input框
10
11
12如何规避上述问题
13 csrf跨站请求伪造校验
14 网站在给用户返回一个具有提交数据功能页面的时候会给这个页面添加一个唯一标识
15 当这个页面朝后端发送post请求的时候,后端会先校验唯一标识,如果唯一标识不对,直接拒绝,返回404
1# form表单(提交数据)
2 {% csrf_token %}
3
4在前端界面input框添加
5<form>
6{% csrf_token %} # 会自动生成一个name=csrfmiddlewaretoken,value='随机字符串'
7input
8
9</form>
ajax添加csrf验证
1# ajax请求
2
3$('#d1').click(function({
4 $.ajax({
5 url:'',
6 type:'post',
7 data:{'name':'json'}
8 success:function(args){
9
10 })
11 }
12}
13))
14
15# 第一种方式:在data添加一组新的数据,名字必须是csrfmiddlewaretoken
16利用标签查找获取页面上的随机字符串
17data:{'name':'json','csrfmiddlewaretoken':$(['name=csrfmiddlewaretoken']).val()}
18
19# 第二种方式:使用模板语法提供的快捷方式(不实用前后端分离的情况)
20data:{'name':'json','csrfmiddlewaretoken':{{ csrf_token }}}
21
22# 第三种方式:导入js模板(通用版)
23模块代码如下:
24
25使用:1.在目录下建立一个static文件夹存放静态文件
26 2.可以进行二次分类(css、js、img等等)
27 3.在js文件夹中新建一个py文件,将下述内容导入其中
28 4.在配置文件,setting.py中添加
29 STATICFILES_DIRS=[
30 os.path.join(BASE_DIR,'static')
31 ] # 动态获取
32
33 5.使用script标签动态的导入
csrf校验模块
1function 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}
16var csrftoken = getCookie('csrftoken');
17
18
19function csrfSafeMethod(method) {
20 // these HTTP methods do not require CSRF protection
21 return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
22}
23
24$.ajaxSetup({
25 beforeSend: function (xhr, settings) {
26 if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
27 xhr.setRequestHeader("X-CSRFToken", csrftoken);
28 }
29 }
30});
31
32
33更多详情,见django官方文档https://docs.djangoproject.com/en/1.11/ref/csrf/
csrf验证相关装饰器之FBV
1'''
2需求:
3 1. 全部都验证,但是就有几个方法不验证
4 2. 全部都不验证,但是,就有几个方法需要验证
5'''
6# 如何实现(借助模块)
7 from django.views.decorators.csrf import csrf_exempt, csrf_protect
8 csrf_protect: 需要验证
9 csrf_exempt:不需要验证
10
11# 针对fbv直接在有需求的函数添加装饰器即可
12
13只有登录功能需要验证,把csrf中间件注掉,在需要验证的函数上添加装饰器
14@csrf_protect
15def login(request):
16 pass
17
csrf验证相关装饰器之CBV
1# 针对cbv:
2
3 我们通过测试发现:
4
5 # csrf_exempt只支持在dispatch上添加装饰器
6 # csrf_protect,三种方式都可以
7
8from django.views.decorators.csrf import csrf_exempt, csrf_protect
9
10
11 @method_decorator(csrf_exempt) # 第一种方式不行
12 def post(self, request):
13 return HttpResponse('post')
14
15 @method_decorator(csrf_protect, name='post') # 第二种方式也不行
16 class TestView(View):
17
18 @method_decorator(csrf_protect) # 第三种可以
19 def dispatch(self, request, *args, **kwargs):
20 return super().dispatch(request, *args, **kwargs)
21 可以变形为:
22 @method_decorator(csrf_protect, name='dispatch')
23 class TestView(View):
给类添加装饰器的方法
1在类上添加装饰器的三种方法
2
3from django.views import View
4class login(View):
5 def get(self,request):
6 return HttpResponse('from get')
7
8 def post(self,request):
9 return HttpResponse('from post')
10
11 都需要借助from django.decorators import method_decorator
12
13 1.直接在需要添加装饰器的函数上加
14 @method_decorator(装饰器名称)
15 def get(self,request):
16 return HttpResponse('from get')
17
18 2.在类上添加
19 @method_decorator(装饰器名称,name='get') # 可支持多个
20 class login(View):
21 pass
22 3.在dispatch(源代码)# 可以应用于所有的方法
23 def dispatch():
24 pass
25
Auth模块
1# 创建django项目之后,执行数据库迁移命令,会生成一堆表,这些表里面有auth开头的,django开头的
2django_session
3auth_user
4
5# 项目创建完成之后,路由里面是不是有一个admin/, 访问admin就可以快速打开一个后台管理页面
6
7登录该后台需要的用户名和密码参考的数据从auth_user表来,并且还要是超级管理员才能登录
8
9先执行迁移命令
10
11# 创建超级管理员
12python3 manage.py createsuperuser
13
14
15 '''
16 使用Auth模块用就用全套
17 '''
Auth模块之注册功能
1注册功能
2 from django.contrib.auth.models import User # User就是auth_user表
3
4 #创建普通用户
5 User.objects.create_user(username=username, password=password)
6
7 #创建超级用户(邮箱是必填的)
8 User.objects.create_superuser(username=username, password=password,email=123@qq.com)
9
10 不能用create,密码是明文,会无法校验User.objects.create_user(username=username, password=password)
Auth模块的登录功能
1from django.contrib import auth
21. 登录功能
3
4 # 去哪个表查
5 # 密码如何比对
6 # 比对用户名密码, 用户名和密码必须同时传入,不能只传一个
7 user_obj = auth.authenticate(request, username=username, password=password)
8 如果用户名、密码正确返回值是user_obj一个用户对象,错误则返回None
9
10 # 保存用户状态
11 auth.login(request, user_obj) # request.session['username'] = user_obj
12
13 '''
14 只要执行了auth.login(request,user_obj),那么,在全局任何地方都可以通过
15 request.user拿到用户对象, 封装到request.user
16 '''
17
18 3. 验证是否登录
19 res = request.user.is_authenticated() # 验证是否登录成功
20 返回true和false
Auth模块之验证登录的装饰器
1 验证登录的装饰器
2
3 from django.contrib.auth.decorators import login_required
4
5 直接在函数添加@login_required(login_url='/login/')
6 # 局部配置:让用户没有登录的情况下直接跳到这个网址login_url='/login/'
7
8 全局配置:在settings.py文件中配置LOGIN_URL='/login/'
9 # 让用户没有登录的情况下直接跳到这个网址login_url后面的网址,这时局部配置中的login_url就可以省略
10
11 '''
12 如果局部和全局都设置了网址,以局部网址为准
13 两者各有优缺点
14 全局好处在于无法重复写代码,跳转单一
15 不同的视图函数在没有登录的情况下可以跳转到不同页面
16
17 '''
Auth模块之修改密码
1 修改密码
2 # 1. 验证老密码是否正确
3 is_right = request.user.check_password(old_pwd) # 自动加密,比对密码
4 返回值为布尔值
5
6 # 2. 真正的修改数据库
7 request.user.set_password(new_pwd) # 只是修改了属性,并没有操作数据库
8 request.user.save() # 这句话才真正操作数据库
验证模块的取消功能
1 注销功能
2 auth.logout(request) # 类似request.session.flush()
扩展 auth_user 字段
1# 第一种方式:一对一关联表(不推荐)
2 建立外键关系
3
4# 第二种方式,使用面向对象的继承
5from django.contrib.auth.models import AbstractUser
6 1. 扩展auth_user表要继承AbstractUser类
7 2. 扩展字段不要动原来的字段,你只需要在继承的类中写你自己想要扩展的字段
8 3. 生成一个新表,该表有原来的字段加上你扩展出来的字段
9 4. 在settings.py中加个配置:
10 AUTH_USER_MODEL = '应用名.表名'
11 5. 扩展表之后,auth_user表就没有了
12
13'''
14如果继承了AbstractUser
15那么在执行数据库迁移命令的时候auth_user表就不会再创建出来了
16而userinfo表中会出现auth_user表所有字段外加自己扩展的字段
17这么做的好处在于你能够直接点击你自己的表更加快速的完成操作及扩展
18
19前提:
20 1、在继承之前没有执行过数据库迁移命令
21 auth_user表没有被创建,如果当时库已经创建了,那么只能换一个库
22 2、继承的类里面不要覆盖AbstractUser里面的字段名
23 表里面的字段都不要动,只扩展额外字段即可
24 3、需要在配置文件中告诉django你要用UsefInfo替代auth_user
25 AUTH_USER_MODEL = '应用名.表名' # app01.UsefInfo
26'''