4.1.python第四章:Django高级

Django高级应用

Cookie

Cookie的原理

  1. Cookie是由服务器产生,存储在浏览器中的键值对数据
  2. 每个域名的Cookie都相对独立
  3. 浏览器访问域名为A的erl地址,会把A域名下的Cookie一起传到服务器
  4. Cookie可以设置过期时间

Cookie的设置和获取

cookie的设置:
    response = HttpResponse()
    response.set_cookie([key],[value],max_age=60*60)
    return response

注:max_age:默认为none(关闭浏览器则删除Cookie),单位秒:60*60表示3600秒即一个小时

取cookie:
    value = request.COOKIES.get([key],None)
url:
    urlpatterns = [
        path('',views.index_handler,name='index'),
        re_path('set_cookie/(.+)/(.+)',views.set_cookie_handeler,name='set_cookie'),
        # 正则传递两个参数,前一个是key,后一个是value
        re_path('get_cookie/(.+)',views.get_cookie_handler,name='get_cookie'),
]

view:
    def index_handler(request):
        return HttpResponse('index')


    def set_cookie_handeler(request,key,value):
        response = HttpResponse()
        response.set_cookie(key, value, max_age=60 * 60)
        return response


    def get_cookie_handler(request,key):
        value = request.COOKIES.get(key)
        return HttpResponse(value)

Cookie的安全性

  1. Cookie存储在客户端,即浏览器,所以具有不安全性
  2. 对于敏感的数据,应该加密,或者保存在服务端

Session

Session的原理

  1. Session基于Cookie
  2. Session将敏感的数据以加密的方式保存在服务器
  3. 原理:浏览器访问服务器,发送用户名密码等私密数据,服务器将私密数据加密、过期时间保存进数据库并返回一个sessionID,在浏览器下一次访问时,会向服务器发送sessionID,服务器接收到ID后到数据库比对拿到加密后的私密数据并解密。

Session 的设置和获取

设置:
    request.session[key] = value

设置过期时间:
    request.session.set_expiry(60*60)

获取:
    value = request.session.get(key) # 如果没有这个key则返回None
首先设置数据库,在项目setting中设置:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'localhost',
            'PORT':'3306',
            'NAME':'django3',
            'USER':'root',
            'PASSWORD':'123456',
        }
    }

url:
    urlpatterns = [
        re_path('set_session/(.+)/(.+)', views.set_session_handeler, name='set_session'),
        re_path('get_session/(.+)', views.get_session_handler, name='get_session'),
    ]
view:
    def set_session_handeler(request,key,value):
        request.session[key] = value
        return HttpResponse('设置成功')


    def get_session_handler(request,key):
        value = request.session.get(key)
        return HttpResponse(value)

flush()和clear()命令

  1. request.session.flush()删除表数据
  2. request.session.clear()清空sessionID对应的数据

Django连接Redis服务

Redis特点

  1. Redis是一种非关系型数据库
  2. 数据读写速度快
  3. 可以存储的数据量小

Redis服务环境搭建

  1. 安装Redis(环境变量)
  2. 安装包:
    pip install redis
    pip install django-redis
    pip install django-redis-sessions

Settings配置

    SESSION_ENGINE = 'redis_sessions.session' # 选择Redis存储session
    SESSION_REDIS_HOST = 'localhost' # Redis主机地址
    SESSION_REDIS_PORT = '6379' # redis端口号
    SESSION_REDIS_DB = 0 # 数据库编号:0-11
    SESSION_REDIS_PASSWORD = '' # 登录密码

表单数据的提交和接收

表单编写

    form 标签
        提交地址:action
        提交方法:method
        提交文件:enctype="multipart/form-data"
如:
<form action="www.edu.csdn.net"method="post"enctype="multipart/form-data">

    input:
        type = "text"       文本输入框
        type = "password"   密码输入框
        type = "radio"      单选框
        type = "checkbox"   复选框
        type = "file"       文件框
        type = "button"     按钮
        type = "submit"     提交
        type = "reset"      重置

    下拉框:
    <select>
        <option>1</option>
        <option>2</option>
    </select>

    大文本:
    <textarea cols="列数" rows="行数"></textarea>


GET\POST请求方式

  1. GET请求提交的数据参数放在url中
  2. POST请求提交的数据被加密,url中无法看到

后台数据获取

GET:
    value = request.GET.get([key],[默认值])
    key不存在以默认值进行填充
    values = request.GET.getlist([key])

POST:
    value = request.POST.get([key],[默认值])
    values = request.POST.getlist([key])

注意:post请求,需要在表单中加入{%csrf_token%},或者取消csrf中间件

CSRF跨域攻击

CSRF攻击原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t1AqDKEN-1603422469011)(D:\git笔记\徐仓鼠的学习笔记\python\CSRF攻击.png)]

  1. 首先用户C浏览并登录了受信任站点A;
  2. 登录信息验证通过以后,站点A会在返回给浏览器的信息中带上已登录的cookie,cookie信息会在浏览器端保存一定时间(根据服务端设置而定);
  3. 完成这一步以后,用户在没有登出(清除站点A的cookie)站点A的情况下,访问恶意站点B;
  4. 这时恶意站点 B的某个页面向站点A发起请求,而这个请求会带上浏览器端所保存的站点A的cookie;
  5. 站点A根据请求所带的cookie,判断此请求为用户C所发送的。

因此,站点A会报据用户C的权限来处理恶意站点B所发起的请求,而这个请求可能以用户C的身份发送 邮件、短信、消息,以及进行转账支付等操作,这样恶意站点B就达到了伪造用户C请求站点 A的目的。

预防CSRF攻击的方法

  1. 尽量使用POST,限制GET
    GET接口太容易被拿来做CSRF攻击。接口最好限制为POST使用,GET则无效,降低攻击风险。
    当然POST并不是万无一失,攻击者只要构造一个form就可以,但需要在第三方页面做,这样就增加暴露的可能性。

  2. 将cookie设置为HttpOnly
    CRSF攻击很大程度上是利用了浏览器的cookie,为了防止站内的XSS漏洞盗取cookie,需要在cookie中设置“HttpOnly”属性,这样通过程序(如JavaScript脚本、Applet等)就无法读取到cookie信息,避免了攻击者伪造cookie的情况出现。
    在Java的Servlet的API中设置cookie为HttpOnly的代码如下:

    response.setHeader( "Set-Cookie", "cookiename=cookievalue;HttpOnly")
    
  3. 增加token
    CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于cookie中,因此攻击者可以在不知道用户验证信息的情况下直接利用用户的cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信总不存在于cookie之中。鉴于此,系统开发人员可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务端进行token校验,如果请求中没有token或者token内容不正确,则认为是CSRF攻击而拒绝该请求。
    假设请求通过POST方式提交,则可以在相应的表单中增加一个隐藏域:

    <input type="hidden" name="_toicen" value="tokenvalue"/>
    

    token的值通过服务端生成,表单提交后token的值通过POST请求与参数一同带到服务端,每次会话可以使用相同的token,会话过期,则token失效,攻击者因无法获取到token,也就无法伪造请求。
    在session中添加token的实现代码:

    HttpSession session = request.getSession();
    Object token = session.getAttribute("_token");
    if(token == null I I "".equals(token)) {
        session.setAttribute("_token", UUID.randomUUIDO .toString());
    }
    
  4. 通过Referer识别
    根据HTTP协议,在HTTP头中有一个字段叫Referer,它记录了该HTTP请求的来源地址。在通常情况下,访问一个安全受限的页面的请求都来自于同一个网站。比如某银行的转账是通过用户访问 http://www.xxx.com/transfer.do 页面完成的,用户必须先登录 www.xxx.com ,然后通过单击页面上的提交按钮来触发转账事件。当用户提交请求时,该转账请求的Referer值就会是提交按钮所在页面的URL(本例为 www.xxx.com/transfer.do )。如果攻击者要对银行网站实施CSRF攻击,他只能在其他网站构造请求,当用户通过其他网站发送请求到银行时,该请求的Referer的值是其他网站的地址,而不是银行转账页面的地址。因此,要防御CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值即可,如果是以www.xx.om域名开头的地址,则说明该请求是来自银行网站自己的请求,是合法的;如果Referer是其他网站,就有可能是CSRF攻击,则拒绝该请求。
    取得HTTP请求Referer:

    String referer = request.getHeader("Referer");
    

模型类多表操作

模型类一对多、多对多

  1. 外键种类

    关键字说明
    ForeignKey一对多
    ManytoManyField多对多
    OneToOneField一对一
  2. 外键的常用参数

    Django语法

    关键字说明
    to引用的模型类(自关联"self")
    on_delete外键约束:
    【1】models.CSDCADE 级联操作(多对一,一的一方删除,多的一方也删除
    【2】models.PROTECT 报异常(被引用的一方不能被删除)
    【3】models.SET_NULL 设置为null(多对一,一的一方删除,多的一方外键为null)
    【4】models.DO_NOTHING 什么也不做
    related_name反向引用,如果两个表间有多种外键关系,需要指明related_name如果指向,默认是[模型类小写]_set

    MYSQL语法

    级联类型解释
    on delete restrict默认值,抛异常
    on delete cascade如果主表被引用的外键删除,相关联的表的记录也会被删除
    on delete set null如果主表被引用的外键删除,相关联的表的外键设置为空
    on delete no action什么也不做

(1) 模型表中的一对多操作

    User2表结构:username
    News表结构:topic,sender外键指向User2的ID

    当执行完:
        user = User2()
        user.username='user2'
        user.save()
        news=News()
        news.topic = 'topic2'
        news.sender = user
        news.save()
    后:
        news.sender
        # 显示结果<User2: User2 object (ID值)>
        news.sender.username
        # 显示结果'user2'


        user.news_set 这就是反向引用
        # 显示结果 <django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager object at 0x0000000003B75EC8>
        user.news_set.all()
        # 显示结果<QuerySet [<News: News object (2)>]>
        user.news_set.all()[0]
        #显示结果<News: News object (2)>
        user.news_set.all()[0].topic
        # 显示结果'topic2'

(2) 模型表中的多对多操作

    class User2(models.Model):
        username = models.CharField(max_length=16)
        # 一个用户可以收藏多个帖子,一个帖子可被多个用户收藏

    class News(models.Model):
        topic = models.CharField(max_length=100)
        # 一个用户可以发送多个帖子,一个帖子只能由一个用户发送,即(一)News对(多)User2
        sender = models.ForeignKey(to=User2,on_delete=models.CASCADE,related_name='sender_set')# 一个用户被删除,那么他发的所有帖子都会被删除
        collectors = models.ManyToManyField(to=User2,related_name='collectors_set')
        # 此时出现一个问题,原先user查看发送的帖子是user.news_set,
        # 但是现在有两层对应关系,所以再用news_set就不行了,
        # 那么怎么区分发的帖子和收藏的帖子?加入参数related_name

    交互模式中,添加收藏帖子有两种操作
    1.user.collectors_set.add(news)
    2.news.collectors.add(user)
    查看user收藏的帖子:user.collectors_set.all()
    查看帖子被哪些user收藏:news.collectors.all()

(3) 模型表中的自关联

    class Area(models.Model):
        name = models.CharField(max_length=10)
        pArea = models.ForeignKey(to='self',null=True,on_delete=models.CASCADE)


        area = Area
        area.name='beijing'
        area.save()
        area2 = Area
        area2.name='chaoyang'
        area2.pArea=area 朝阳的父级地区为北京
        area2.save()

        area.area_set.all() 查看北京子地区都有哪些
        area2.pArea 查看朝阳的父级地区

中间件Django Middelware应用

中间件的原理

Django框架原理:浏览器发送请求到服务器,服务器根据路由映射path将请求对接到对应的处理器,由处理器具体处理后再返回响应
中间件原理:在浏览器发送请求到服务器和服务器返回响应时可以进行拦截,并加以修饰

中间件的使用

  1. 定义中间件
    class middleware(MiddlewareMixin):
        def __init__(self,get_response=None):
            super().__init__(get_response)
            # 初始化中间件
            print('init_middleware')
        def process_request(self, request):
            # 没有return或return None 继续调用其他视图
            # return response 则直接返回响应
            print('process_request')
        def process_response(self, request, response):
            # 必须return response
            print('process_response')
            return response
  1. 在settings中配置中间件
    MIDDLEWARE = [‘middleware.middleware’] 类名.方法名
    est(self, request):
    # 没有return或return None 继续调用其他视图
    # return response 则直接返回响应
    print(‘process_request’)
    def process_response(self, request, response):
    # 必须return response
    print(‘process_response’)
    return response

2. 在settings中配置中间件
   MIDDLEWARE = ['middleware.middleware'] 类名.方法名
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值