s14_09_cookie session csrf

- 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,...)
        rep.set_signed_cookie(key,value,salt='加密盐',...)
        
            参数:
                key,              键
                value='',         值
                max_age=None,     超时时间
                expires=None,     超时时间(IE requires expires, so set it if hasn't been already.)
                path='/',         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
                domain=None,      Cookie生效的域名
                secure=False,     https传输
                httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

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

        <script src='/static/js/jquery.cookie.js'></script>
        $.cookie("list_pager_num", 30,{ path: '/' });
        
        response = HttpResponse(a)
        response.set_cookie()
        return response
        # cokies 通过响应头返回
        
        
        response = HttpResponse(a)
        response['name'] = ’alex‘
        # 自己写响应头
        
    -  示例:
    
        user_info ={
            'dachengzi':{'pwd':'123123'},
            'kangbazi':{'pwd':'456789'}
        }

        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('/index/')
                    res.set_cookie('username',u)
                    return res
                else:
                    return render(request,'login.html')

        def index(request):
            v = request.COOKIES.get('username')
            if not v:
                return redirect('/login/')
            return render(request,'index.html',{'current_user':v})

        def cookie(request):

            request.COOKIES
            request.COOKIES['username']
            request.COOKIES.get('username')

            response =render(request,'index.html')
            response =redirect('/index/')

            # 设置cockie,关闭浏览器失效
            response.set_cookie('key','value')

            # 设置cockie,n秒后失效
            response.set_cookie('username','value',max_age=10)

            # 设置cockie,截止时间失效
            import datetime
            current_date = datetime.datetime.utcnow()
            current_date = current_date + datetime.timedelta(seconds=10)
            response.set_cookie('username','value',expires=current_date)

            # 应用:每页显示多少数量
            response.set_cookie('username','value',path='/')
            return  response    
            
    - 用户认证装饰器
    
        FBV:
            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})
    
        CBV:
                
            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

            from django import views
            from django.utils.decorators import method_decorator



            # 仅对get

            class Order(views.View):
                @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})                        
                                    
                                    
            # 通过dispatch 对全部

            class Order(views.View):

                @method_decorator(auth)
                def dispatch(self, request, *args, **kwargs):
                    return super(Order,self).dispatch(request, *args, **kwargs)

                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})                        

            # 对全部方法        
            @method_decorator(auth,name='dispatch')
            class Order(views.View):

                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

    基于Cookie做用户验证时:敏感信息不适合放在cookie中
    
    a. Session原理
        Cookie是保存在用户浏览器端的键值对
        Session是保存在服务器端的键值对
    
    b. Cookie和Session对比
    
    c. Session配置(缺少cache)
    
    d. 示例:实现两周自动登陆
            - request.session.set_expiry(60*10)
            - SESSION_SAVE_EVERY_REQUEST = True

    PS: cookie中不设置超时时间,则表示关闭浏览器自动清除
    
    
    - session依赖于cookie
    
    - 服务器session
        request.session.get()
        request.session[x] = x
        
        request.session.clear()
        
    - 配置文件中设置默认操作(通用配置):
    
        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_COOKIE_AGE = 1209600                 # Session的cookie失效日期(2周)(默认)
        SESSION_EXPIRE_AT_BROWSER_CLOSE = False      # 是否关闭浏览器使得Session过期(默认)
        # set_cookie('k',123)
        SESSION_SAVE_EVERY_REQUEST = False           # 是否每次请求都保存Session,默认修改之后才保存(默认)

    - 引擎的配置
    
        详见别人博客

    - 扩展:Session用户验证
        
        def login(func):
            def wrap(request, *args, **kwargs):
                # 如果未登陆,跳转到指定页面
                if request.path == '/test/':
                    return redirect('http://www.baidu.com')
                return func(request, *args, **kwargs)
            return wrap            
            
- session用户登陆及CSRF相关示例

    # urls.py

        url(r'^login/$', views.login),
        url(r'^index/', views.index),
        url(r'^logout/', views.logout),
    
    # views.py
    
        from django.shortcuts import render,redirect,HttpResponse

        # Create your views here.
        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':
                    # 生成随机字符串,写到用户cookie,保存到session
                    # 随机字符串中 设置相关内容
                    # makemigrations, migrate
                    request.session['username'] = user
                    request.session['is_login'] = True
                    if request.POST.get('rmb')=='1':
                        request.session.set_expiry(10)
                    return redirect('/index/')
                else:
                    return render(request,'login.html')
        # from django.views.decorators.csrf import csrf_exempt,csrf_protect
        # @csrf_exempt
        # @csrf_protect
        # 局部设置
        def index(request):
            # 获取当前用户字符串,并获取对应信息
            if request.session.get('is_login',None):
                return render(request,'index.html')
            else:
                return HttpResponse('go back')
    
    # index.html
    
        def logout(request):
            request.session.clear()
            return redirect('/login/')            
            
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            <h1>welcome:{{ request.session.username }}</h1>
            <a href="/logout/">leave</a>
        </body>
        </html>

    # login.html

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
        <form action="/login/"method="POST">
            {% csrf_token %}
            <input type="text" name="user">
            <input type="text" name="pwd">
            <input type="checkbox"name="rmb"value="1">10秒免登陆
            <input type="submit">
            <input id="btn" type="button"value="A提交">

            <script src="/static/jquery-1.12.4.js"></script>
            <script src="/static/jquery.cookie.js"></script>
            <script>
                $(function () {
                    $.ajaxSetup({
                        // 全局配置,对所有ajax配置请求头,携带csrf-token
                        beforeSend:function (xhr,settings) {
                            xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
                        }
                    });
        {#            var csrf_tonken = $.cookie('csrftoken');#}
                    // get等请求时不携带x-csrftoken,需要在此做出判断,具体见其他。
                    $('#btn').click(function () {
                        $.ajax({
                            url:'/login/',
                            type:'POST',
        {#                    headers:{'X-CSRFtoken': $.cookie('csrftoken')},#}
                            data:{'user':'root','pwd':'123'},
                            success: function (arg) {

                            }
                        })
                    });
                })
            </script>
        </form>
        </body>
        </html>
            
-  CSRF

    a. CSRF原理
    b. 无CSRF时存在隐患
        # django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。
        
        # 而对于django中设置防跨站请求伪造功能有分为全局和局部。

            全局:
              中间件 django.middleware.csrf.CsrfViewMiddleware

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

        # from django.views.decorators.csrf import csrf_exempt,csrf_protect
        
    c. Form提交(CSRF)
    d. Ajax提交(CSRF)
       CSRF请求头 X-CSRFToken

    - 应用

    1、普通表单
        
        veiw中设置返回值:
          return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))  
             或者
             return render(request, 'xxx.html', data)
          
        html中设置Token:
          {% csrf_token %}

    2、Ajax

        # 对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。

        view.py
            
            from django.template.context import RequestContext
            # Create your views here.
          
            def test(request):
              
                if request.method == 'POST':
                    print request.POST
                    return HttpResponse('ok')
                return  render_to_response('app01/test.html',context_instance=RequestContext(request))

        text.html
            
            <!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>

    3、更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax

            由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。

posted @ 2020-01-18 21:37  badweather  阅读(94)  评论(0编辑  收藏  举报