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是什么?
就是一个类,可以校验字段(前台传过来的字段)
-怎么用:
-校验字段功能:
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