django第13天(auth组件,forms组件,中间件,csrf)

django第13天(auth组件,forms组件)

auth组件

-auth组件

-auth是什么?
-django内置的用户认证系统,可以快速的实现,登录,注销,修改密码....

-怎么用?
-(1)先创建超级用户:
-python3 manage.py createsuperuser
-输入用户名,邮箱(可以不输入),密码,敲回车,这样就创建出一个超级用户
-也就是在auth_user这个表中插入了一条数据(密码是加密的,所以我不能手动插入)

-(2)验证用户:
-from django.contrib import auth
-user = auth.authenticate(request, username=name, password=pwd)
-相当于在查询:user=models.User.objects.filter(name=name,pwd=pwd).first()
-如果校验通过,会返回一个user对象,通过判断user对象,校验是否验证成功

-(3)登录
-auth.login(request,user)
-其实就是在session中写了一条数据

-(4)一旦登录成功,调了这个函数login(request,user)
-以后再视图类,函数中的request对象中,就有一个user对象,就是当前登录的用户对象
-如果没有登录,request.user=AnonymousUser,匿名用户

-(5)注销
-auth.logout(request)
-内部:调用了request.session.flush(),删除了登录状态

-(6)登录认证装饰器
-from django.contrib.auth.decorators import login_required
-@login_required(redirect_field_name='eee',login_url='/login/')
-redirect_field_name:修改?后面的key值,
-login_url:如果没有登录,跳转到的页面
-可以局部配置
-可以全局配置(在setting中)
	# 全局的配置,如果没有登录,跳到这个路由
	LOGIN_URL='/login/'

-(7)创建用户:
-from django.contrib.auth.models import User				
- 创建超级用户和普通用户
# 不能用create
# user=User.objects.create(username=name,password=pwd)
# 创建超级用户
# user=User.objects.create_superuser(username=name,password=pwd)
# 创建普通用户
user=User.objects.create_user(username=name,password=pwd)

-(8)校验密码
-request.user.check_password(pwd)
-先拿到用户(可以是登录用户,可以现查)

-(9)修改密码:
-user.set_password(pwd)
-user.save()
-注意:一定要调用save(),否则是不保存的

-(10)is_authenticated()
-如果通过验证,是true反之false

-(11)其他方法(了解):
-is_active:禁止登录网站(用户还存在,封号)
-is_staff:是否对网站有管理权限(能不能登录admin)

-(12)删除用户
-orm删除

如果想在认证组件上加手机号等其他字段:如何处理
-(1) 定义一个表模型,跟User一对一管理
class UserDetail(models.Model):
phone=models.CharField(max_length=32)
# 一对一跟auth_user表做关联
# 如果是从外部引入的表模型,是不能加引号的
# 如果加引号,只是在当前model找
user=models.OneToOneField(to=User)
-(2)定义一个表模型,继承(AbstractUser)
-from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
# username,password...都有
phone=models.CharField(max_length=32)
sex=models.BooleanField()
-在setting中配置:
AUTH_USER_MODEL ='app01.UserInfo'
-做数据库迁移,以后就没有auth_user这个表了,以后认证组件用的表就是UserInfo
-原来auth中的其他操作:
-authentication
-login
-logout
-set_password
....
---一样用,完全一样
-不一样的地方:
如果之前用到User这个表模型的地方,都换成UserInfo

forms组件

forms组件
-forms是什么?
就是一个类,可以校验字段(前台传过来的字段)

-怎么用:
    -校验字段功能:
        
 
from django import forms
from django.db import models

# Create your models here.

from django.contrib.auth.models import AbstractUser

from django.core.exceptions import ValidationError

-先写一个类,继承Form
class Myform(forms.Form):
    #min_length属性  检验规范:最小长度
    #max_length
    #error_messages:将违反对应规则的错误信息改为中文
    #label 渲染前台信息的时候,将label设置为中文
    #widget = forms.widgets.PasswordInput(attrs = 'class':'form-control')
    #widget 渲染前台时采用密文的方式,还可以设置样式,attrs = 
    #invalid:格式错误,邮箱
    name = forms.CharField(min_length=3, max_length=8, label="姓名",
                           error_messages={
                               'min_length': '长度不短于3',
                               'max_length': '长度不长于8',
                               'required': '不能为空',
                           })
    pwd = forms.CharField(min_length=3, max_length=8, label="密码",
                          widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}),
                          error_messages={
                              'min_length': '长度不短于3',
                              'max_length': '长度不长于8',
                              'required': '不能为空',
                          })
                            
    email = forms.EmailField(label="邮箱",
                             error_messages={
                                 'min_length': '长度不短于3',
                                 'max_length': '长度不长于8',
                                 'required': '不能为空',
                                 'invalid': '格式错误'
                             }         

渲染模板

-渲染模板
-第一种方式:(灵活性最高)
<form action="">
    姓名:{{ myform.name }}
    密码:{{ myform.pwd }}
    邮箱:{{ myform.email }}
    <input type="submit" value="注册">
</form>
                             
                             
-第二种方式:for循环form对象(用的比较多):
<form action="" method="post" novalidate>
    {% for obj in myform %}
      <p>{{obj.label }}:{{ obj }}
          <span>{{ obj.errors.0 }}</span>
      </p>
    {% endfor %}
    <input type="submit" value="注册">
    <span>{{ error_msg }}</span>
</form>		
			
                             
-第三种方式(不建议用):
<form action="" method="post" >
{#    {{ myform.as_p }}#}
{{ myform.as_ul }}
<input type="submit" value="提交">
</form>
    

渲染错误信息

-渲染错误信息
- myforms有errors
-属性(name)也有errors
-错误信息,变成中文:
    - error_messages={'max_length': '最长是8', 'min_length': '最短是3', 'required': '这个必须填','invalid': '不符合邮箱格式'}
    -给input标签指定样式,指定格式:
        -widget=widgets.TextInput(attrs={'class':'form-control'})
        -模板,渲染错误信息:<span>{{ myform.name.errors.0 }}</span>

局部钩子


局部校验,只要form中name校验过了,就可以执行到
#导入validationError
from django.core.exceptions import ValidationError
#编写需要增加校验项的字段
def clean_name(self):
    #取出字段校验通过的信息,用来再进行判断,如果没通过就不会执行到此函数
    name = self.cleaned_data.get('name')
    import re
    pattern = '^\d+'
    if re.match(pattern,name):
        raise ValidationError("不能以数字开头")
    return name

全局钩子

#导入validationError
from django.core.exceptions import ValidationError
#一定会被执行,不管前面是否校验通过
def clean(self):
    pwd = self.cleaned_data.get('pwd')
    re_pwd = self.cleaned_data.get('re_pwd')
    if pwd!=re_pwd:
       raise ValidationError("两次密码不同")#会放在errors的__all__属性里
    return self.cleaned_data

前台
<form action="" method="post" novalidate>
    <form action="">
    {% for obj in myform %}
      <p>{{obj.label }}:{{ obj }}
          <span>{{ obj.errors.0 }}</span>
      </p>
    {% endfor %}
    <input type="submit" value="注册">
    <span>{{ error_msg }}</span>#放在for循环里,会打多次
    </form>
</form>


def register(request):
    if request.method == "GET":
        myform = Myform()
    if request.method == "POST":
        myform = Myform(request.POST)
        if not myform.is_valid():#判断是否通过验证
           # {'__all__': [ValidationError(['两次密码不同'])]}
        	try:
            	error_msg = myform.errors.as_data().['__all__'][0]#errors.as_data()得到的是字典	
            except:
                pass
    return render(request,"register.html",locals())

中间件

## 中间件

​```python
1.中间件是什么:
    请求和响应之间的一道屏障
2.中间件的作用:
    控制请求和响应
3.自定义中间件

一.导入类
from django.utils.deprecation import MiddlewareMixin
二.定义一个我们自己的中间件(类),继承MiddlewareMixin

from django.utils.deprecation import MiddlewareMixin

class Mymiddle1(MiddlewareMixin):
    def process_request(self,request):
        pass
    
    def process_response(self,request,response):
        pass
三.在配置文件中注册自定义中间件

MIDDLEWARE = [
    'app01.mymiddle.Mymiddle1'
]

​```

## 中间件的方法

​```python
   
    process_request(self,request)

    process_view(self, request, callback, callback_args, callback_kwargs)

    process_template_response(self,request,response)

    process_exception(self, request, exception)

    process_response(self, request, response)
​```

## process_request    process_response

​```python

返回值
①process_request 
如果return HttpResponse对象,直接返回,其后的中间件就不起作用了
如果return None(默认就是return none) 继续往下走
②process_reponse
必须要return Httpresponse的对象

执行顺序
中间件的process_request方法是在执行视图函数之前执行的。

当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。

不同中间件之间传递的request都是同一个对象

多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。 
​```

## process_view

​```python
process_view(self, request, view_func, view_args, view_kwargs)

该方法有四个参数

request是HttpRequest对象。

view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)

view_args是将传递给视图的位置参数的列表.

view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)

Django会在调用视图函数之前调用process_view方法。

它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用适当的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。
​```

## process_template_response(了解)

​```python
该方法对视图函数返回值有要求,必须是一个含有render方法类的对象,才会执行此方法



class Test:
    def __init__(self,status,msg):
        self.status=status
        self.msg=msg
    def render(self):
        import json
        dic={'status':self.status,'msg':self.msg}
        return HttpResponse(json.dumps(dic))
    
def index(response):
    return Test(True,'测试')

​```

## 中间件的应用场景

​```python
1.做ip访问频率的限制
某些IP访问服务器的频率过高,进行拦截,比如限制每分钟不能超过20次。


2.url访问过滤

如果用户访问的是login视图(放过)

如果访问其他视图,需要检测是不是有session认证,已经有了放行,没有返回login,这样就省得在多个视图函数上写装饰器了!
​```


CSRF

cross site request
是什么
攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的
原理,你登陆后拿到了服务端的cookie,当你不关闭网站A,打开了黑客网站B,点击了网站B的按钮发请求,请求发到了网站A的服务器,B也带着你的cookie


如何防范:
    1.通过refer
    2.加一个随机字符串检验(加载请求的路径里,加载请求体中)
    3.在请求头加字符串校验


form表单:{% csrf_token %}

视图函数:request.POST.csrfmiddlewaretoken

    
django中的应用:
    1.中间件不注释
    2.以后发post请求,携带那个随机字符串
    

ajax中的应用:
属性选择器:
    
    1.data{
     'csrfmiddlewaretoken':
    $('[name = 'csrfmiddlewaretoken']').val()    
    }
    2.data{
        'csrfmiddlewaretoken':'{{csrf_token}}'
    }
    
    3.
    需要导入插件 jquery.cookie.js
    
    从cookie中取,放入请求头
    var token = $.cookie('csrftoken')
   # var token = '{{csrf_token}}'

   $.ajax(
   {
       headers:{'X-CSRFToken':token}
   })

csrf局部禁用

导一个装饰器
from django.views.decorators.csrf import  csrf_exempt,csrf_protect

#局部禁用装饰器
@csrf_exempt
#局部保护装饰器
@csrf_protect

CBV的局部禁用和局部使用

from django.views import View
from django.utils.decorators import method_decorator
#2.@method_decorator(csrf_protect,name= 'dispatch')加在类上,标注名称
class Csrf_disable(View):
    
    #1.@method_decorator(csrf_protect)加在dispatch方法上
    def dispath(self,request,*args,**kwargs):
        res= super().dispatch(request,*args,**kwargs)
		return res
   
    def get(self,request):
        return 
    
    def post(self,request):
        return

posted @ 2019-03-21 11:38  robertzhou  阅读(305)  评论(0编辑  收藏  举报