8中间件,csrf跨站请求伪造,auth模块

mac2022-06-30  28

昨日内容回顾  多对多三种创建方式   1.全自动    完全依赖于ManyToMany让django orm自动创建第三张表    优势:不需要你创建第三张表  自动创建    不足:第三张表扩展性   2.纯手动    不依赖于ManyToMany,自己创建第三张表,里面是有ForeignKey自己做两张表的关联    优势:第三张可以新增任意字段 扩展性较高    不足:orm查询时较为繁琐   3.半自动(推荐使用 因为可以给你后续的项目迭代提供方便)    依赖于ManyToMany,但是自己创建第三张表    优势:可扩展性高    不足:多对多字段方法不支持了(add,set,remove,clear)    forms组件   forms组件三大功能:    1.渲染前端获取用户输入的标签    2.校验数据    3.展示错误信息    注意:forms组件只能渲染获取用户输入的标签  提交按钮需要用户自己写      1.基本使用    forms组件中所有的字段默认都是必填的(默认就是required=True)    from  django import forms        class MyForm(forms.Form):     username = forms.CharField(max_length=8)     email = forms.EmailField()   2.先生成一个对象    form_obj = MyForm({'username':'jason','email':'123@qq.com'})   3.判断数据是否合法    form_obj.is_valid()    # 只有数据全部满足条件才会返回True   4.获取符合条件的数据    form_obj.cleaned_data   5.获取不符合条件的数据的报错原因    form_obj.errors   6.渲染前端页面  先生成一个空对象 并将对象传递给前端页面    form_obj = MyForm()   7.前端页面有三种渲染方式    1.{{form_obj.as_p}}  # 封装程度太高 可扩展性差    2.{{ form_obj.username.label }}{{form_obj.username}}  # 书写的内容太多了    3. {% for form in form_obj %}  # 使用频率较高      <p> {{form.label}}{{ form }}</p>     {% endfor %}   8.其他属性操作    from  django.forms import widgets    username = forms.CharField(max_length=8,label='用户名',required=False,           error_message={            'max_length':"用户名最大八位",            'required':'用户名不能为空'           },           widget=widgets.TextInput(attrs={'class':'form-control'},           validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')]           )          )   9.钩子函数(Hook)    局部钩子 (针对某一个字段做一些额外的校验)    from app01 import models    def clean_username(self):     # 当前用户名是否已经被注册     username = self.cleaned_data.get('username')     is_user = models.User.objects.filter(username=username)     if is_user:      self.add_error('username','用户名已经存在')     if '西游记' in username:      self.add_error('username','不符合社会主义核心价值观')     return username        全局钩子(针对多个字段的校验)    def clean(self):     password = self.cleaned_data.get('password')     confirm_password = self.cleaned_data.get('confirm_password')     if not password == confirm_password:      self.add_error('confirm_password','两次密码不一致')     return self.cleaned_data   10.其他字段及参数    initial  默认值    如果是单选的话  统一都是forms.ChocieField(      widget=widgets.Select(),      widget=widgets.RadioSelect(),      widget=widgets.CheckboxSelect(),    )       Cookie与Session   由于http协议是无状态      cookie是保存在客户端浏览器上的   session是保存服务端上的   session是依赖于cookie的,所有的保存用户登录状态或者各种校验基本都需要   依赖于cookie      django操作cookie与session    操作的cookie要利用HttpResponse对象    obj = HttpResponse()    obj.set_cookie('k1','v1',max_age=100)    return obj            request.COOKIES.get('k1')        request.session['name'] = 'jason'  # 三件事    # 1.生成一个随机字符串    # 2.将随机字符串和要保存的数据写入django_session表中(django默认session过期时间14天)    # 3.将随机字符串返回给客户端浏览器    """    服务端保存用户信息 不一定非要在django_session表中保存    可以利用其他数据库或者换成作为session的暂存地    """            request.session.get('name')  # 三件事            # 删除当前会话的所有Session数据    request.session.delete()          # 删除当前的会话数据并删除会话的Cookie。    request.session.flush()     这用于确保前面的会话数据不可以再次被用户的浏览器访问     例如,django.contrib.auth.logout() 函数中就会调用它。    # 设置会话Session和Cookie的超时时间    request.session.set_expiry(value)     * 如果value是个整数,session会在些秒数后失效。     * 如果value是个datatime或timedelta,session就会在这个时间后失效。     * 如果value是0,用户关闭浏览器session就会失效。     * 如果value是None,session会依赖全局session失效策略。      利用cookie写了装饰器      作业用session      今日内容   django中间件    django中间件是类似于是django的保安    请求的时候需要先经过中间件才能到达django后端(urls,views,templates,models)    响应走的时候也需要经过中间件才能到达web服务网关接口            django默认的七个中间件     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',        ]               class SecurityMiddleware(MiddlewareMixin):      def __init__(self, get_response=None):       self.sts_seconds = settings.SECURE_HSTS_SECONDS       self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS       self.sts_preload = settings.SECURE_HSTS_PRELOAD       self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF       self.xss_filter = settings.SECURE_BROWSER_XSS_FILTER       self.redirect = settings.SECURE_SSL_REDIRECT       self.redirect_host = settings.SECURE_SSL_HOST       self.redirect_exempt = [re.compile(r) for r in settings.SECURE_REDIRECT_EXEMPT]       self.get_response = get_response      def process_request(self, request):       path = request.path.lstrip("/")       if (self.redirect and not request.is_secure() and         not any(pattern.search(path)           for pattern in self.redirect_exempt)):        host = self.redirect_host or request.get_host()        return HttpResponsePermanentRedirect(         "https://%s%s" % (host, request.get_full_path())        )      def process_response(self, request, response):       if (self.sts_seconds and request.is_secure() and         'strict-transport-security' not in response):        sts_header = "max-age=%s" % self.sts_seconds        if self.sts_include_subdomains:         sts_header = sts_header + "; includeSubDomains"        if self.sts_preload:         sts_header = sts_header + "; preload"        response["strict-transport-security"] = sts_header       if self.content_type_nosniff and 'x-content-type-options' not in response:        response["x-content-type-options"] = "nosniff"       if self.xss_filter and 'x-xss-protection' not in response:        response["x-xss-protection"] = "1; mode=block"       return response          class CsrfViewMiddleware(MiddlewareMixin):       if settings.CSRF_USE_SESSIONS:        request.session[CSRF_SESSION_KEY] = request.META['CSRF_COOKIE']       else:        response.set_cookie(         settings.CSRF_COOKIE_NAME,         request.META['CSRF_COOKIE'],         max_age=settings.CSRF_COOKIE_AGE,         domain=settings.CSRF_COOKIE_DOMAIN,         path=settings.CSRF_COOKIE_PATH,         secure=settings.CSRF_COOKIE_SECURE,         httponly=settings.CSRF_COOKIE_HTTPONLY,        )        # Set the Vary header since content varies with the CSRF cookie.        patch_vary_headers(response, ('Cookie',))      def process_request(self, request):       csrf_token = self._get_token(request)       if csrf_token is not None:        # Use same token next time.        request.META['CSRF_COOKIE'] = csrf_token      def process_view(self, request, callback, callback_args, callback_kwargs):       if getattr(request, 'csrf_processing_done', False):        return None       # Wait until request.META["CSRF_COOKIE"] has been manipulated before       # bailing out, so that get_token still works       if getattr(callback, 'csrf_exempt', False):        return None       # Assume that anything not defined as 'safe' by RFC7231 needs protection       if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):        if getattr(request, '_dont_enforce_csrf_checks', False):         # Mechanism to turn off CSRF checks for test suite.         # It comes after the creation of CSRF cookies, so that         # everything else continues to work exactly the same         # (e.g. cookies are sent, etc.), but before any         # branches that call reject().         return self._accept(request)        if request.is_secure():         # Suppose user visits http://example.com/         # An active network attacker (man-in-the-middle, MITM) sends a         # POST form that targets https://example.com/detonate-bomb/ and         # submits it via JavaScript.         #         # The attacker will need to provide a CSRF cookie and token, but         # that's no problem for a MITM and the session-independent         # secret we're using. So the MITM can circumvent the CSRF         # protection. This is true for any HTTP connection, but anyone         # using HTTPS expects better! For this reason, for         # https://example.com/ we need additional protection that treats         # http://example.com/ as completely untrusted. Under HTTPS,         # Barth et al. found that the Referer header is missing for         # same-domain requests in only about 0.2% of cases or less, so         # we can use strict Referer checking.         referer = force_text(          request.META.get('HTTP_REFERER'),          strings_only=True,          errors='replace'         )         if referer is None:          return self._reject(request, REASON_NO_REFERER)         referer = urlparse(referer)         # Make sure we have a valid URL for Referer.         if '' in (referer.scheme, referer.netloc):          return self._reject(request, REASON_MALFORMED_REFERER)         # Ensure that our Referer is also secure.         if referer.scheme != 'https':          return self._reject(request, REASON_INSECURE_REFERER)         # If there isn't a CSRF_COOKIE_DOMAIN, require an exact match         # match on host:port. If not, obey the cookie rules (or those         # for the session cookie, if CSRF_USE_SESSIONS).         good_referer = (          settings.SESSION_COOKIE_DOMAIN          if settings.CSRF_USE_SESSIONS          else settings.CSRF_COOKIE_DOMAIN         )         if good_referer is not None:          server_port = request.get_port()          if server_port not in ('443', '80'):           good_referer = '%s:%s' % (good_referer, server_port)         else:          # request.get_host() includes the port.          good_referer = request.get_host()         # Here we generate a list of all acceptable HTTP referers,         # including the current host since that has been validated         # upstream.         good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)         good_hosts.append(good_referer)         if not any(is_same_domain(referer.netloc, host) for host in good_hosts):          reason = REASON_BAD_REFERER % referer.geturl()          return self._reject(request, reason)        csrf_token = request.META.get('CSRF_COOKIE')        if csrf_token is None:         # No CSRF cookie. For POST requests, we insist on a CSRF cookie,         # and in this way we can avoid all CSRF attacks, including login         # CSRF.         return self._reject(request, REASON_NO_CSRF_COOKIE)        # Check non-cookie token for match.        request_csrf_token = ""        if request.method == "POST":         try:          request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')         except IOError:          # Handle a broken connection before we've completed reading          # the POST data. process_view shouldn't raise any          # exceptions, so we'll ignore and serve the user a 403          # (assuming they're still listening, which they probably          # aren't because of the error).          pass        if request_csrf_token == "":         # Fall back to X-CSRFToken, to make things easier for AJAX,         # and possible for PUT/DELETE.         request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')        request_csrf_token = _sanitize_token(request_csrf_token)        if not _compare_salted_tokens(request_csrf_token, csrf_token):         return self._reject(request, REASON_BAD_TOKEN)       return self._accept(request)      def process_response(self, request, response):       if not getattr(request, 'csrf_cookie_needs_reset', False):        if getattr(response, 'csrf_cookie_set', False):         return response       if not request.META.get("CSRF_COOKIE_USED", False):        return response       # Set the CSRF cookie even if it's already set, so we renew       # the expiry timer.       self._set_token(request, response)       response.csrf_cookie_set = True       return response                   class AuthenticationMiddleware(MiddlewareMixin):      def process_request(self, request):       assert hasattr(request, 'session'), (        "The Django authentication middleware requires session middleware "        "to be installed. Edit your MIDDLEWARE%s setting to insert "        "'django.contrib.sessions.middleware.SessionMiddleware' before "        "'django.contrib.auth.middleware.AuthenticationMiddleware'."       ) % ("_CLASSES" if settings.MIDDLEWARE is None else "")       request.user = SimpleLazyObject(lambda: get_user(request))                    django中间件中有五个用户可以自定义的方法           django中间件可以用来做什么(***********************)       1.网站全局的身份校验,访问频率限制,权限校验...只要是涉及到全局的校验你都可以在中间件中完成       2.django的中间件是所有web框架中 做的最好的                  需要我们掌握的方法有       1.process_request()方法        规律         1.请求来的时候 会经过每个中间件里面的process_request方法(从上往下)         2.如果方法里面直接返回了HttpResponse对象 那么会直接返回 不再往下执行          基于该特点就可以做访问频率限制,身份校验,权限校验                 2.process_response()方法        规律         1.必须将response形参返回 因为这个形参指代的就是要返回给前端的数据         2.响应走的时候 会依次经过每一个中间件里面的process_response方法(从下往上)               需要了解的方法       3.process_view()        1.在路由匹配成功执行视图函数之前 触发        走完process_request方法就执行process_view(),然后执行process_response()方法               4.process_exception()        1.当你的视图函数报错时  就会自动执行               5.process_template_response()        1.当你返回的HttpResponse对象中必须包含render属性才会触发        def index(request):         print('我是index视图函数')         def render():          return HttpResponse('什么鬼玩意')         obj = HttpResponse('index')         obj.render = render         return obj     总结:你在书写中间件的时候 只要形参中有repsonse 你就顺手将其返回 这个reponse就是要给前端的消息               如何自定义我们自己的中间件,研究这上面五个方法都有哪些特点********       1.如果你想让你写的中间件生效 就必须要先继承MiddlewareMixin       2.在注册自定义中间件的时候 一定要确保路径不要写错           案例:       from django.shortcuts import HttpResponse       from django.utils.deprecation import MiddlewareMixin       class MyMdd(MiddlewareMixin):        def process_request(self,request):         print('我是第一个中间件process_request')        def process_response(self,request,response):         print('我是第一个中间件里面的process_response')         return response            def process_view(self,request,view_func,view_args,view_kwargs):          print(view_func)          print(view_args)          print(view_kwargs)          print('我是第一个中间件里的process_view')         def process_exception(self,request, exception): 当你的视图函数报错时  就会自动执行          print('我是第一个中间件里面的process_exception')                    class MyMdd1(MiddlewareMixin):        def process_request(self,request):         print('我是第二个中间件process_request')         #当中间件里面的process_request方法返回了一个HttpResponse对象         # 那么就不会再继续向下执行,而是直接跳到同级别的procsee_response直接往回走         return HttpResponse('嘿嘿嘿')        def process_response(self,request,response):         print('我是第二个中间件里面的process_response')         return response       class MyMdd2(MiddlewareMixin):        def process_request(self,request):         print('我是第三个中间件process_request')        def process_response(self,request, response):# 括号里面别忘记response         print('我是第三个中间件里面的process_response')         return response    # 此时的response就是视图函数里返回的Http                       csrf跨站请求伪造     钓鱼网站     通过制作一个跟正儿八经的网站一模一样的页面,骗取用户输入信息 转账交易     从而做手脚      转账交易的请求确确实实是发给了中国银行,账户的钱也是确确实实少了      唯一不一样的地方在于收款人账户不对     内部原理      在让用户输入对方账户的那个input上面做手脚      给这个input不设置name属性,在内部隐藏一个实现写好的name和value属性的input框      这个value的值 就是钓鱼网站受益人账号           防止钓鱼网站的思路      网站会给返回给用户的form表单页面 偷偷塞一个随机字符串      请求到来的时候 会先比对随机字符串是否一致  如果不一致  直接拒绝(403)      例如用户在登录中国银行的时候,会产生一个唯一的随机的字符串,在下一次用户登录的时候将携带这个wo      能识别的唯一的字符串与我储存的字符串进行一一比对,比对上说明客户登录的就是我网站的用户,比对不上就是钓鱼网站           该随机字符串有以下特点      1.同一个浏览器每一次访问都不一样      2.不同浏览器绝对不会重复         1.form表单发送post请求的时候  需要你做得仅仅书写一句话    {% csrf_token %}*******    在你返回给用户的form表单中,会偷偷的塞一对键值对,塞一组信息,当用户再次发送请求时,我会偷偷的先    拿到那对键值,进行比对,如果比对上,说明你是我本网站用户,接下来在进行用户操作,然后在进行校验    即比对成功,才会让你输入用户名,每一次的token都不一样,钓鱼网站token和正规网站token不一样,正规的网站它会记录自己的token,    钓鱼网站的token如果和正规网站token一样,但是这个token不是正规网站给你的,所以无法访问   2.ajax发送post请求 如何避免csrf校验    1.现在页面上写{% csrf_token %},利用标签查找  获取到该input键值信息     {'username':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}     $('[name=csrfmiddlewaretoken]').val()     #固定用法         2.直接书写'{{ csrf_token }}'     {'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}     {{ csrf_token }}        3.你可以将该获取随机键值对的方法 写到一个js文件中,之后只需要导入该文件即可     新建一个js文件 存放以下代码 之后导入即可     function getCookie(name) {      var cookieValue = null;      if (document.cookie && document.cookie !== '') {       var cookies = document.cookie.split(';');       for (var i = 0; i < cookies.length; i++) {        var cookie = jQuery.trim(cookies[i]);        // Does this cookie string begin with the name we want?        if (cookie.substring(0, name.length + 1) === (name + '=')) {         cookieValue = decodeURIComponent(cookie.substring(name.length + 1));         break;        }       }      }      return cookieValue;     }     var csrftoken = getCookie('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);      }       }     });               1.当你网站全局都需要校验csrf的时候 有几个不需要校验该如何处理   2.当你网站全局不校验csrf的时候 有几个需要校验又该如何处理    from django.utils.decorators import method_decorator     from django.views.decorators.csrf import csrf_exempt,csrf_protect    # 这两个装饰器在给CBV装饰的时候 有一定的区别    如果是csrf_protect 那么有三种方式     # 第一种方式     # @method_decorator(csrf_protect,name='post')  # 有效的     class MyView(View):      # 第三种方式      # @method_decorator(csrf_protect)      def dispatch(self, request, *args, **kwargs):       res = super().dispatch(request, *args, **kwargs)       return res      def get(self,request):       return HttpResponse('get')      # 第二种方式      # @method_decorator(csrf_protect)  # 有效的      def post(self,request):       return HttpResponse('post')          如果是csrf_exempt 只有两种(只能给dispatch装)   特例    @method_decorator(csrf_exempt,name='dispatch')  # 第二种可以不校验的方式    class MyView(View):     # @method_decorator(csrf_exempt)  # 第一种可以不校验的方式     def dispatch(self, request, *args, **kwargs):      res = super().dispatch(request, *args, **kwargs)      return res     def get(self,request):      return HttpResponse('get')     def post(self,request):      return HttpResponse('post')      总结 装饰器中只有csrf_exempt是特例,其他的装饰器在给CBV装饰的时候 都可以有三种方式      课后作业:    将昨天的写的登陆认证装饰器 加载CBV上       auth模块    如果你想用auth模块   那么你就用全套                跟用户相关的功能模块     用户的注册 登陆 验证 修改密码 ...        执行数据库迁移命令之后  会生成很多表  其中的auth_user是一张用户相关的表格    添加数据     createsuperuser  创建超级用户 这个超级用户就可以拥有登陆django admin后台管理的权限      auth模块的功能    查询用户     from django.contrib import auth     user_obj = auth.authenticate(username=username,password=password)  # 必须要用 因为数据库中的密码字段是密文的 而你获取的用户输入的是明文    记录用户状态     auth.login(request,user_obj)  # 将用户状态记录到session中    判断用户是否登录     print(request.user.is_authenticated)  # 判断用户是否登录  如果是你们用户会返回False    用户登录之后 获取用户对象     print(request.user)  # 如果没有执行auth.login那么拿到的是匿名用户    校验用户是否登录     from django.contrib.auth.decorators import  login_required     @login_required(login_url='/xxx/')  # 局部配置     def index(request):      pass          # 全局配置  settings文件中     LOGIN_URL = '/xxx/'    验证密码是否正确     request.user.check_password(old_password)    修改密码      request.user.set_password(new_password)     request.user.save()  # 修改密码的时候 一定要save保存 否则无法生效    退出登陆     auth.logout(request)  # request.session.flush()    注册用户      # User.objects.create(username =username,password=password)  # 创建用户名的时候 千万不要再使用create 了      # User.objects.create_user(username =username,password=password)  # 创建普通用户      User.objects.create_superuser(username =username,password=password,email='123@qq.com')  # 创建超级用户  邮箱必填         自定义auth_user表    from django.contrib.auth.models import AbstractUser    # Create your models here.    # 第一种 使用一对一关系  不考虑      # 第二种方式   使用类的继承    class Userinfo(AbstractUser):     # 千万不要跟原来表中的字段重复 只能创新     phone = models.BigIntegerField()     avatar = models.CharField(max_length=32)        # 一定要在配置文件中 告诉django    # 告诉django  orm不再使用auth默认的表  而是使用你自定义的表    AUTH_USER_MODEL = 'app01.Userinfo'  # '应用名.类名'         1.执行数据库迁移命令    所有的auth模块功能 全部都基于你创建的表    而不再使用auth_user              settings功能插拔式源码    参考django 配置文件中的 中间件等功能模块    

转载于:https://www.cnblogs.com/Fzhiyuan/p/11587871.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)