zoukankan      html  css  js  c++  java
  • 【python】-- Django 分页 、cookie、Session、CSRF

    Django  分页 、cookie、Session、CSRF

    一、分页

    分页功能在每个网站都是必要的,下面主要介绍两种分页方式:

    1、Django内置分页

    from django.shortcuts import render
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    
    L = []
    for i in range(999):
        L.append(i)
    
    def index(request):
        current_page = request.GET.get('p')
    
        paginator = Paginator(L, 10)
        # per_page: 每页显示条目数量
        # count:    数据总个数
        # num_pages:总页数
        # page_range:总页数的索引范围,如: (1,10),(1,200)
        # page:     page对象
        try:
            posts = paginator.page(current_page)
            # has_next              是否有下一页
            # next_page_number      下一页页码
            # has_previous          是否有上一页
            # previous_page_number  上一页页码
            # object_list           分页之后的数据列表
            # number                当前页
            # paginator             paginator对象
        except PageNotAnInteger:
            posts = paginator.page(1)
        except EmptyPage:
            posts = paginator.page(paginator.num_pages)
        return render(request, 'index.html', {'posts': posts})
    views.py
    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    <ul>
        {% for item in posts %}
            <li>{{ item }}</li>
        {% endfor %}
    </ul>
    
    <div class="pagination">
          <span class="step-links">
            {% if posts.has_previous %}
                <a href="?p={{ posts.previous_page_number }}">Previous</a>
            {% endif %}
              <span class="current">
                Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
              </span>
              {% if posts.has_next %}
                  <a href="?p={{ posts.next_page_number }}">Next</a>
              {% endif %}
          </span>
    
    </div>
    </body>
    </html>
    HTML
    from django.shortcuts import render
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    
    
    class CustomPaginator(Paginator):
        def __init__(self, current_page, max_pager_num, *args, **kwargs):
            """
            :param current_page: 当前页
            :param max_pager_num:最多显示的页码个数
            :param args:
            :param kwargs:
            :return:
            """
            self.current_page = int(current_page)
            self.max_pager_num = max_pager_num
            super(CustomPaginator, self).__init__(*args, **kwargs)
    
        def page_num_range(self):
            # 当前页面
            # self.current_page
            # 总页数
            # self.num_pages
            # 最多显示的页码个数
            # self.max_pager_num
            print(1)
            if self.num_pages < self.max_pager_num:
                return range(1, self.num_pages + 1)
            print(2)
            part = int(self.max_pager_num / 2)
            if self.current_page - part < 1:
                return range(1, self.max_pager_num + 1)
            print(3)
            if self.current_page + part > self.num_pages:
                return range(self.num_pages + 1 - self.max_pager_num, self.num_pages + 1)
            print(4)
            return range(self.current_page - part, self.current_page + part + 1)
    
    
    L = []
    for i in range(999):
        L.append(i)
    
    def index(request):
        current_page = request.GET.get('p')
        paginator = CustomPaginator(current_page, 11, L, 10)
        # per_page: 每页显示条目数量
        # count:    数据总个数
        # num_pages:总页数
        # page_range:总页数的索引范围,如: (1,10),(1,200)
        # page:     page对象
        try:
            posts = paginator.page(current_page)
            # has_next              是否有下一页
            # next_page_number      下一页页码
            # has_previous          是否有上一页
            # previous_page_number  上一页页码
            # object_list           分页之后的数据列表
            # number                当前页
            # paginator             paginator对象
        except PageNotAnInteger:
            posts = paginator.page(1)
        except EmptyPage:
            posts = paginator.page(paginator.num_pages)
    
        return render(request, 'index.html', {'posts': posts})
    扩展内置分页:views.py
    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    
    <ul>
        {% for item in posts %}
            <li>{{ item }}</li>
        {% endfor %}
    </ul>
    
    <div class="pagination">
    <span class="step-links">
    {% if posts.has_previous %}
        <a href="?p={{ posts.previous_page_number }}">Previous</a>
    {% endif %}
    
        {% for i in posts.paginator.page_num_range %}
            <a href="?p={{ i }}">{{ i }}</a>
        {% endfor %}
    
        {% if posts.has_next %}
            <a href="?p={{ posts.next_page_number }}">Next</a>
        {% endif %}
    </span>
    
    <span class="current">
    Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
    </span>
    
    </div>
    </body>
    </html>
    扩展内置分页:Html

    2、自定义分页

    需求:

    1、设定每页显示数据条数

    2、用户输入页码(第一页、第二页...)

    3、设定显示多少页号

    4、获取当前数据总条数

    5、根据设定显示多少页号和数据总条数计算出,总页数

    6、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置

    7、在数据表中根据起始位置取值,页面上输出数据

    8、输出分页html,如:[上一页][1][2][3][4][5][下一页]

    2.1、templates下的模板:

    <li>{{ item }}</li>
    li.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            .pagination .page{
                display: inline-block;
                padding: 5px;
                background-color: cyan;
                margin: 5px;
            }
            .pagination .page.active{
                background-color: brown;
                color: white;
            }
        </style>
    </head>
    <body>
        <ul>
            {% for item in li %}
                {% include 'li.html' %}
            {% endfor %}
        </ul>
    
        <div class="pagination">
            {{ page_str }}
        </div>
    </body>
    </html>
    user_list.html

    2.2、新增utils目录,创建分页工具pagination.py文件。

    from django.utils.safestring import mark_safe  # 导入mark_safe函数
    
    
    class Page:
        def __init__(self, current_page, data_count, per_page_count=10, pager_num=7):
            self.current_page = current_page  # 当前页
            self.data_count = data_count      # 总页数
            self.per_page_count = per_page_count   # 每页显示数据
            self.pager_num = pager_num             # 前端展示的分页数
    
        @property            # 转换成静态属性
        def start(self):
            """
            定义每页展示数据的开始下标
            :return:
            """
            return (self.current_page - 1) * self.per_page_count
    
        @property
        def end(self):
            """
            定义每页展示数据的结束下标
            :return:
            """
            return self.current_page * self.per_page_count
    
        @property
        def total_count(self):
            """
            定义总页数
            :return:
            """
            v, y = divmod(self.data_count, self.per_page_count)   # 内置函数divmod 能够整除返回True,不能整除返回False
            if y:
                v += 1
            return v
    
        def page_str(self, base_url):
            """
            定义分页规则
            :param base_url:
            :return:
            """
            page_list = []
    
            if self.total_count < self.pager_num:
                start_index = 1
                end_index = self.total_count + 1
            else:
                if self.current_page <= (self.pager_num + 1) / 2:
                    start_index = 1
                    end_index = self.pager_num + 1
                else:
                    start_index = self.current_page - (self.pager_num - 1) / 2
                    end_index = self.current_page + (self.pager_num + 1) / 2
                    if (self.current_page + (self.pager_num - 1) / 2) > self.total_count:
                        end_index = self.total_count + 1
                        start_index = self.total_count - self.pager_num + 1
    
            if self.current_page == 1:
                prev = '<a class="page" href="javascript:void(0);">上一页</a>'
            else:
                prev = '<a class="page" href="%s?p=%s">上一页</a>' % (base_url, self.current_page - 1,)
            page_list.append(prev)
    
            for i in range(int(start_index), int(end_index)):
                if i == self.current_page:
                    temp = '<a class="page active" href="%s?p=%s">%s</a>' % (base_url, i, i)
                else:
                    temp = '<a class="page" href="%s?p=%s">%s</a>' % (base_url, i, i)
                page_list.append(temp)
    
            if self.current_page == self.total_count:
                nex = '<a class="page" href="javascript:void(0);">下一页</a>'
            else:
                nex = '<a class="page" href="%s?p=%s">下一页</a>' % (base_url, self.current_page + 1,)
            page_list.append(nex)
    
            jump = """
            <input type='text'  /><a onclick='jumpTo(this, "%s?p=");'>GO</a>
            <script>
                function jumpTo(ths,base){
                    var val = ths.previousSibling.value;
                    location.href = base + val;
                }
            </script>
            """ % (base_url,)
    
            page_list.append(jump)
            # django从view向template传递HTML字符串的时候,django默认不渲染此HTML,原因是为了防止这段字符串里面有恶意攻击的代码(XSS)
            # mark_safe这个函数就是确认这段HTML字符串是安全的,Django会才会渲染此HTML
            page_str = mark_safe("".join(page_list))
    
            return page_str
    pagination.py

    2.3、app下的views.py:

    from django.shortcuts import render
    from utils import pagination
    
    LIST = []
    for i in range(500):
        LIST.append(i)
    
    
    def user_list(request):
        current_page = request.GET.get('p', 1)
        current_page = int(current_page)
    
        # val = request.COOKIES.get('per_page_count', 10)
        # val = int(val)
        page_obj = pagination.Page(current_page, len(LIST))
    
        data = LIST[page_obj.start:page_obj.end]
    
        page_str = page_obj.page_str("/app1/user_list/")
    
        return render(request, 'user_list.html', {'li': data, 'page_str': page_str})
    views.py

    二、Cookie

    Cookie 是在 HTTP 协议下,服务器或脚本可以维护客户工作站上信息的一种方式。Cookie 是由 Web 服务器保存在用户浏览器(客户端)上的小文本文件,它可以包含有关用户的信息。无论何时用户链接到服务器,Web 站点都可以访问 Cookie 信息,因此用户不用每次登陆都需要输入账号密码。

    1、获取Cookie:

    request.COOKIES['key']
    request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
        """ 
      参数:
            default: 默认值
               salt: 加密盐
            max_age: 后台控制过期时间
        """

    2、设置Cookie:

    rep = HttpResponse(...) 或 rep = render(request, ...) #创建对象
     
    rep.set_cookie(key,value,...) #明文Cookie设置方式
    rep.set_signed_cookie(key,value,salt='加密盐',...) #加密加盐Cookie设置方式
        """
        参数:
            key,              键
            value='',         值
            max_age=None,     超时时间  
            expires=None,     超时时间(IE requires expires, so set it if hasn't been already.)
            max_age与expires的区别:max_age用秒设置超时时间,N秒后失效,expires用datetime设置超时时间,到截至时间后失效
            path='/',         Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
            domain=None,      Cookie生效的域名
            secure=False,     https传输
            httponly=False    只能http协议传输,当httponly=True时,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
        """

    3、前端页面操作Cookie

    由于Cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作Cookie。

    JavaScript操作Cookie:
    #获取cookie并赋值给变量
    var strCookie=document.cookie
    #修改cookie中的id值
    document.cookie="id=88";
    #设置终止时间
    ###获取当前时间
    var date=new Date();
    var expireDays=10;
    ###将date设置为10天以后的时间
    date.setTime(date.getTime()+expireDays*60*1000);
    ###将id和name两个cookie设置为10天后过期
    document.cookie="id=77; name=bill; expires="+date.toUTCString();
    
    
    Jquery操作Cookie:
    相对于JS操作cookie,Jquery操作Cookie就简单很多
    <script src='/static/js/jquery.cookie.js'></script>   #导入jquery.cookie.js文件,此文件在官网下载
    $.cookie("list_pager_num", 30,{ path: '/' }); 
    

    4、根据cookie值显示定制条数示例:

    在上面自定义分页示例的基础上,根据cookie值进行定制条数数据显示。

     4.1、templates下的模板:

    <li>{{ item }}</li>
    li.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style>
            .pagination .page{
                display: inline-block;
                padding: 5px;
                background-color: cyan;
                margin: 5px;
            }
            .pagination .page.active{
                background-color: brown;
                color: white;
            }
        </style>
    </head>
    <body>
        <ul>
            {% for item in li %}
                {% include 'li.html' %}
            {% endfor %}
        </ul>
    
        <div>
            <select id="ps" onchange="changePageSize(this)">
                <option value="10">10</option>
                <option value="30">30</option>
                <option value="50">50</option>
                <option value="100">100</option>
            </select>
        </div>
    
        <div class="pagination">
            {{ page_str }}
        </div>
        <script src="/static/jquery-1.12.4.js"></script>
        <script src="/static/jquery.cookie.js"></script>
        <script>
            //将选择框的值设置为cookie,在Views中就可以接收cookie
            function changePageSize(ths){
                var v = $(ths).val();
                $.cookie('per_page_count',v);
                location.reload(); //页面重新加载
            }
            //将多选框的值更改为最新的值
             $(function(){
                    var v = $.cookie('per_page_count');
                    $('#ps').val(v);
            });
    
        </script>
    </body>
    </html>
    user_list.html

    4.2、utils目录下pagination.py文件

    from django.utils.safestring import mark_safe  # 导入mark_safe函数
    
    
    class Page:
        def __init__(self, current_page, data_count, per_page_count=10, pager_num=7):
            self.current_page = current_page  # 当前页
            self.data_count = data_count      # 总页数
            self.per_page_count = per_page_count   # 每页显示数据
            self.pager_num = pager_num             # 前端展示的分页数
    
        @property            # 转换成静态属性
        def start(self):
            """
            定义每页展示数据的开始下标
            :return:
            """
            return (self.current_page - 1) * self.per_page_count
    
        @property
        def end(self):
            """
            定义每页展示数据的结束下标
            :return:
            """
            return self.current_page * self.per_page_count
    
        @property
        def total_count(self):
            """
            定义总页数
            :return:
            """
            v, y = divmod(self.data_count, self.per_page_count)   # 内置函数divmod 能够整除返回True,不能整除返回False
            if y:
                v += 1
            return v
    
        def page_str(self, base_url):
            """
            定义分页规则
            :param base_url:
            :return:
            """
            page_list = []
    
            if self.total_count < self.pager_num:
                start_index = 1
                end_index = self.total_count + 1
            else:
                if self.current_page <= (self.pager_num + 1) / 2:
                    start_index = 1
                    end_index = self.pager_num + 1
                else:
                    start_index = self.current_page - (self.pager_num - 1) / 2
                    end_index = self.current_page + (self.pager_num + 1) / 2
                    if (self.current_page + (self.pager_num - 1) / 2) > self.total_count:
                        end_index = self.total_count + 1
                        start_index = self.total_count - self.pager_num + 1
    
            if self.current_page == 1:
                prev = '<a class="page" href="javascript:void(0);">上一页</a>'
            else:
                prev = '<a class="page" href="%s?p=%s">上一页</a>' % (base_url, self.current_page - 1,)
            page_list.append(prev)
    
            for i in range(int(start_index), int(end_index)):
                if i == self.current_page:
                    temp = '<a class="page active" href="%s?p=%s">%s</a>' % (base_url, i, i)
                else:
                    temp = '<a class="page" href="%s?p=%s">%s</a>' % (base_url, i, i)
                page_list.append(temp)
    
            if self.current_page == self.total_count:
                nex = '<a class="page" href="javascript:void(0);">下一页</a>'
            else:
                nex = '<a class="page" href="%s?p=%s">下一页</a>' % (base_url, self.current_page + 1,)
            page_list.append(nex)
    
            jump = """
            <input type='text'  /><a onclick='jumpTo(this, "%s?p=");'>GO</a>
            <script>
                function jumpTo(ths,base){
                    var val = ths.previousSibling.value;
                    location.href = base + val;
                }
            </script>
            """ % (base_url,)
    
            page_list.append(jump)
            # django从view向template传递HTML字符串的时候,django默认不渲染此HTML,原因是为了防止这段字符串里面有恶意攻击的代码(XSS)
            # mark_safe这个函数就是确认这段HTML字符串是安全的,Django会才会渲染此HTML
            page_str = mark_safe("".join(page_list))
    
            return page_str
    pagination.py

    4.3、app下的views.py:

    def cookie(request):
        #
        # request.COOKIES
        # request.COOKIES['username111']
        request.COOKIES.get('username111')
    
        response = render(request,'index.html')
        response = redirect('/index/')
        # 设置cookie,关闭浏览器失效
        response.set_cookie('key',"value")
        # 设置cookie, N秒只有失效
        response.set_cookie('username111',"value",max_age=10)
        # 设置cookie, 截止时间失效
        import datetime
        current_date = datetime.datetime.utcnow()
        current_date = current_date + datetime.timedelta(seconds=5)
        response.set_cookie('username111',"value",expires=current_date)
        response.set_cookie('username111',"value",max_age=10)
    
        # request.COOKIES.get('...')
        # response.set_cookie(...)
        obj = HttpResponse('s')
    
        obj.set_signed_cookie('username',"kangbazi",salt="asdfasdf")
        request.get_signed_cookie('username',salt="asdfasdf")
    
        return response
    views.py

    5、cookie模拟登陆示例:

    5.1、templates下模板:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <form action="/login/" method="POST">
            <input type="text" name="username" placeholder="用户名" />
            <input type="password" name="pwd" placeholder="密码" />
            <input type="submit" />
        </form>
    </body>
    </html>
    login.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1>欢迎登录:{{ current_user }}</h1>
    </body>
    </html>
    home

    5.2、views.py:

    user_info = {
        'dachengzi': {'pwd': "123123"},
        'kanbazi': {'pwd': "kkkkkkk"},
    }
    def login(request):
        if request.method == "GET":
            return render(request,'login.html')
        if request.method == "POST":
            u = request.POST.get('username')
            p = request.POST.get('pwd')
            dic = user_info.get(u)
            if not dic:
                return render(request,'login.html')
            if dic['pwd'] == p:
                res = redirect('/home/')
                # res.set_cookie('username111',u,max_age=10)   #设置cookie N秒后失效 
                # import datetime
                # current_date = datetime.datetime.utcnow()
                # current_date = current_date + datetime.timedelta(seconds=5)
                # res.set_cookie('username111',u,expires=current_date)      #设置cookie 到截至时间后失效 
                res.set_cookie('username111',u)
                res.set_cookie('user_type',"asdfjalskdjf",httponly=True) # 只能http协议传输,当httponly=True时,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
                return res
            else:
                return render(request,'login.html')
    views.py

    6、CBV和FBV用户认证装饰器

    6.1、FBV (Function Base VIew)在view(视图)中装饰器编写逻辑:

    def auth(func):
        def inner(reqeust,*args,**kwargs):
            v = reqeust.COOKIES.get('username111')
            if not v:
                return redirect('/login/')
            return func(reqeust, *args,**kwargs)
        return inner
    
    @auth
    def index(reqeust):
        # 获取当前已经登录的用户
        v = reqeust.COOKIES.get('username111')
        return render(reqeust,'index.html',{'current_user': v})

    6.2、CBV(Class Base Viev)在view(视图)中装饰器编写逻辑:

    from django import views
    from django.utils.decorators import method_decorator  #导入method_decorator函数,此函数时Django工具包中用于视图中类的装饰器函数
    
    def auth(func):
        def inner(reqeust,*args,**kwargs):
            v = reqeust.COOKIES.get('username111')
            if not v:
                return redirect('/login/')
            return func(reqeust, *args,**kwargs)
        return inner
    
    
    @method_decorator(auth,name='dispatch') #第三种装饰方法,在类上添加上装饰器
    class Order(views.View):
    
        # @method_decorator(auth)  #第二种装饰方法,在dispatch函数上添加装饰器,因为dispatch函数会在类中所有函数执行前先行执行一遍
        # def dispatch(self, request, *args, **kwargs):
        #     return super(Order,self).dispatch(request, *args, **kwargs)
    
        # @method_decorator(auth)  #第一种装饰方法,在需要装饰的上添加装饰器
        def get(self,reqeust):
            v = reqeust.COOKIES.get('username111')
            return render(reqeust,'index.html',{'current_user': v})
    
        def post(self,reqeust):
            v = reqeust.COOKIES.get('username111')
            return render(reqeust,'index.html',{'current_user': v})
    

      

    三、session

    Session存储在服务器端,一般放置在服务器的内存中(为了高速存取),Sessinon在用户访问第一次访问服务器时创建,需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session,可调用request.getSession(true)强制生成Session。

    Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:

    • 数据库(默认)
    • 缓存
    • 文件
    • 缓存+数据库
    • 加密cookie
     1 Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
     2  
     3 a. 配置 settings.py
     4  
     5     SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
     6      
     7     SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
     8     SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
     9     SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
    10     SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
    11     SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
    12     SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
    13     SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
    14     SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)
    15  
    16  
    17  
    18 b. 使用
    19  
    20     def index(request):
    21         # 获取、设置、删除Session中数据
    22         request.session['k1']
    23         request.session.get('k1',None)
    24         request.session['k1'] = 123
    25         request.session.setdefault('k1',123) # 存在则不设置
    26         del request.session['k1']
    27  
    28         # 所有 键、值、键值对
    29         request.session.keys()
    30         request.session.values()
    31         request.session.items()
    32         request.session.iterkeys()
    33         request.session.itervalues()
    34         request.session.iteritems()
    35  
    36  
    37         # 用户session的随机字符串
    38         request.session.session_key
    39  
    40         # 将所有Session失效日期小于当前日期的数据删除
    41         request.session.clear_expired()
    42  
    43         # 检查 用户session的随机字符串 在数据库中是否
    44         request.session.exists("session_key")
    45  
    46         # 删除当前用户的所有Session数据
    47         request.session.delete("session_key")
    48  
    49         request.session.set_expiry(value)
    50             * 如果value是个整数,session会在些秒数后失效。
    51             * 如果value是个datatime或timedelta,session就会在这个时间后失效。
    52             * 如果value是0,用户关闭浏览器session就会失效。
    53             * 如果value是None,session会依赖全局session失效策略。
    数据库Session
     1 a. 配置 settings.py
     2  
     3     SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
     4     SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
     5  
     6  
     7     SESSION_COOKIE_NAME = "sessionid"                        # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
     8     SESSION_COOKIE_PATH = "/"                                # Session的cookie保存的路径
     9     SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
    10     SESSION_COOKIE_SECURE = False                             # 是否Https传输cookie
    11     SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http传输
    12     SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
    13     SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否关闭浏览器使得Session过期
    14     SESSION_SAVE_EVERY_REQUEST = False                        # 是否每次请求都保存Session,默认修改之后才保存
    15  
    16  
    17  
    18 b. 使用
    19  
    20     同上
    缓存Session
     1 a. 配置 settings.py
     2  
     3     SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
     4     SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()                                                            # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
     5  
     6  
     7     SESSION_COOKIE_NAME = "sessionid"                          # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
     8     SESSION_COOKIE_PATH = "/"                                  # Session的cookie保存的路径
     9     SESSION_COOKIE_DOMAIN = None                                # Session的cookie保存的域名
    10     SESSION_COOKIE_SECURE = False                               # 是否Https传输cookie
    11     SESSION_COOKIE_HTTPONLY = True                              # 是否Session的cookie只支持http传输
    12     SESSION_COOKIE_AGE = 1209600                                # Session的cookie失效日期(2周)
    13     SESSION_EXPIRE_AT_BROWSER_CLOSE = False                     # 是否关闭浏览器使得Session过期
    14     SESSION_SAVE_EVERY_REQUEST = False                          # 是否每次请求都保存Session,默认修改之后才保存
    15  
    16 b. 使用
    17  
    18     同上
    文件Session
    1 数据库用于做持久化,缓存用于提高效率
    2  
    3 a. 配置 settings.py
    4  
    5     SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎
    6  
    7 b. 使用
    8  
    9     同上
    缓存+数据库Session
    1 a. 配置 settings.py
    2      
    3     SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎
    4  
    5 b. 使用
    6  
    7     同上
    加密cookie Session

     更多session参考:参考一参考二

    1、session免密登录+10秒超时示例:

    1.1、templates 下的模板文件:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <form action="/login/" method="POST">
            <input type="text" name="user" />
            <input type="text" name="pwd" />
            <input type="checkbox" name="rmb" value="1" /> 10秒免登录
            <input type="submit" value="提交" />
            <input id="btn1" type="button" value="按钮" />
            <input id="btn2" type="button" value="按钮" />
        </form>
    
        <script src="/static/jquery-1.12.4.js"></script>
        <script src="/static/jquery.cookie.js"></script>
    </body>
    </html>
    login.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <h1>欢迎登录:{{ username }}, {{ request.session.username }}</h1>
        <a href="/logout/">注销</a>
    </body>
    </html>
    index.html

     1.2、views.py:

    from django.shortcuts import render,redirect,HttpResponse
    
    def login(request):
        if request.method == "GET":
            return render(request,'login.html')
        elif request.method == "POST":
            user = request.POST.get('user')
            pwd = request.POST.get('pwd')
            if user == 'root' and pwd == "123":
                # session中设置值  Django自动产生4步操作(1、生成随机字符串 2、写到用户浏览器cookie 3、保存在session中 4、在随机字符串对应字典中设置相应值)
                request.session['username'] = user
                request.session['is_login'] = True
                if request.POST.get('rmb', None) == '1':
                    # 超时时间
                    request.session.set_expiry(10)
                return redirect('/index/')
            else:
                return render(request,'login.html')
    
    def index(request):
        # session中获取值
        if request.session.get('is_login', None):
            # {'username': request.session['username']}这个字典数据其实可以不用传递,因为request本身就包含了session值,
            # 在HTML中可以直接通过request.session.username获取用户名
            return render(request, 'index.html', {'username': request.session['username']})
        else:
            return HttpResponse('gun')
    
    # 注销
    def logout(request):
        # del request.session['username']  # 删除一个指定session用户
        request.session.clear()            # 清楚全部session用户
        return redirect('/login/')
    views.py

     注、在运行Django工程示例前需要运行如下命令,生成表结构,session会默认保存在db.sqlite3数据库文件中。

    python3 manage.py  makemigrations #相当于在该app的migrations目录,记录下该app下modes.py所有表结构类型的改动(普通增删改查不记录)
    python3 manage.py  migrate        #将刚刚对于表结构的改动作用至数据库

     

    四、CSRF

    CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。

    之前的Django博文,都是基于在settings.py文件中,注释掉CSRF中间件进行的。

    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',
    ]

    注:现在开始之后的博文都是去掉CSRF中间件注释进行演示。

    django中设置防跨站请求伪造功能有分为全局和局部: 

    全局:
      中间件 django.middleware.csrf.CsrfViewMiddleware
    
    局部:
      from django.views.decorators.csrf import csrf_exempt,csrf_protect
      @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
      @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

    1、生成csrf_token:

    在Django中可以通过{% csrf_token %} 生成csrftoken来防范CSRF攻击,但是要在后续的request请求中需要带上csrftoken参数才能通过CSRF中间件防御机制,进入view视图中进行处理。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <form action="/login/" method="POST">
            <!--在Django中可通过%配合csrf_token字段可生成csrf_token字符串,会在form表单中生成一个隐藏的input框如下:
            <input type="hidden" name="csrfmiddlewaretoken" value="6CAO0tE8oqIsehJFR9VojmS307XRfK91GkxRHutKvwj5nSQgI6KDZZL4hLkAorNo">
            还会在cookie中生成{csrftoken:gQgbSGTiXtnqTeKD0jRbq6ZGsrdiWiJZQydezHIU4zY32PReRgGq6JSHJ5A15Znm}-->
            {% csrf_token %}
            <input type="text" name="user" />
            <input type="text" name="pwd" />
            <input type="checkbox" name="rmb" value="1" /> 10秒免登录
            <input type="submit" value="提交" />
        </form>
        </script>
    </body>
    </html>
    生成csrftoken

     2、csrf_token 提交给后台的三种方式:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title></title>
     6 </head>
     7 <body>
     8     <form action="/login/" method="POST">
     9         <!--在Django中可通过%配合csrf_token字段可生成csrf_token字符串,会在form表单中生成一个隐藏的input框如下:
    10         <input type="hidden" name="csrfmiddlewaretoken" value="6CAO0tE8oqIsehJFR9VojmS307XRfK91GkxRHutKvwj5nSQgI6KDZZL4hLkAorNo">
    11         还会在cookie中生成{csrftoken:gQgbSGTiXtnqTeKD0jRbq6ZGsrdiWiJZQydezHIU4zY32PReRgGq6JSHJ5A15Znm}-->
    12         {% csrf_token %}
    13         <input type="text" name="user" />
    14         <input type="text" name="pwd" />
    15         <input type="checkbox" name="rmb" value="1" /> 10秒免登录
    16         <input type="submit" value="提交" />                                <!-- 第一种提交csrf_token的方式 通过from表单的形式-->
    17         <input id="btn1" type="button" value="按钮" />
    18         <input id="btn2" type="button" value="按钮" />
    19     </form>
    20 
    21     <script src="/static/jquery-1.12.4.js"></script>
    22     <script src="/static/jquery.cookie.js"></script>
    23     <script>
    24       //  第二种提交csrf_token的方式   在每个ajax请求之前,将cookie中的csrftoken值添加至请求头中,ajaxSetup类似于unittest框架中的setup,在每个case运行之前运行一遍
    25         $(function(){
    26             $.ajaxSetup({
    27                 beforeSend: function(xhr,settings){   // xhr 是XMLHttpRequest()对象,settings是Django的配置文件,settings.py每次运行都会将settings加载在内存之中
    28 
    29 
    30                     xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'));
    31                 }
    32             });
    33 
    34             // <!-- 第三种提交csrf_token的方式   通过ajax形式将cookie中的csrftoken值添加至请求头中-->
    35             // <!-- 但是第三种提交方式不好的地方就是需要不断的添加ajax请求,有一个提交按钮,就要新增一个ajax请求-->
    36             $('#btn1').click(function () {
    37                 $.ajax({
    38                     url: '/login/',
    39                     type:"GET",
    40                     data: {'user': 'root', 'pwd': '123'},
    41                     // headers: {'X-CSRFtoken': $.cookie('csrftoken')},  //X-CSRFtoken 这key是固定的不能改变
    42                     success:function(arg){
    43 
    44                     }
    45                 })
    46             });
    47         })
    48     </script>
    49 </body>
    50 </html>
    三种方式

     注:解释 ajax 将csrftoken值添加至请求头中,为什么对应的key是 X-CSRFtoken:

    from django.conf import settings
    print(settings.CSRF_HEADER_NAME)
    
    #输出打印结果  HTTP_X_CSRFTOKEN
    View Code

    通过打印结果发现值是 HTTP_X_CSRFTOKEN,这个就是csrftoken请求头对应的key,HTTP是因为Django会默认将收到的每个请求都会加上HTTP的缘故。因此对应的真实key是X_CSRFTOKEN,但是如果真的就把请求头中的key写成X_CSRFTOKEN的话,后台是接收不到的,因为无法识别下划线_,因此需要将X_CSRFTOKEN写成X-CSRFTOKEN。(X-CSRFTOKEN这个作为key是可以请求的,但是为了命名规范会写成X-CSRFtoken)

    3、根据请求方式决定是否提交csrftoken值

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        {% csrf_token %}
      
        <input type="button" onclick="Do();"  value="Do it"/>
      
        <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
        <script src="/static/plugin/jquery/jquery.cookie.js"></script>
        <script type="text/javascript">
            var csrftoken = $.cookie('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);
                    }
                }
            });
            function Do(){
      
                $.ajax({
                    url:"/app01/test/",
                    data:{id:1},
                    type:'POST',
                    success:function(data){
                        console.log(data);
                    }
                });
      
            }
        </script>
    </body>
    </html>
    View Code

    更多CSRF参考:点击

  • 相关阅读:
    spring整合activemq发送MQ消息[Topic模式]实例
    Activemq消息持久化
    Activemq消息类型
    spring整合activemq发送MQ消息[queue模式]实例
    activemq安装与简单消息发送接收实例
    metaq安装实例
    持续集成工具Hudson安装实例
    nexus安装实例
    sonar的安装与代码质量检测实例
    dubbo发布web服务实例
  • 原文地址:https://www.cnblogs.com/Keep-Ambition/p/8783549.html
Copyright © 2011-2022 走看看