django 中间件以及auth
CBV加装饰器
# 写一个装饰器验证session
from functool import wraps
def login_auth(func):
@wraps(func)
def inner(request,*args,**kwargs):
if request.session.get('is_login'):
return func(request,*args,**kwargs)
else:
return redirect('/login/')
return inner
# 写一个类作为网站主页,必须登陆才能访问
# 给里面的get,post方法加装饰器
class Home(View):
def get(self,request):
pass
def post(self,request):
pass
# 两种加装饰器的方法
# 1,类名上面加装饰器
from django.utils.decoration import method_decorator
@method_decorator(login_auth,name='get') # 加在类上面的话,必须通过name指定给谁加
class Home(View):
def get(self,request):
pass
def post(self,request):
pass
# 2,方法上面加,不要用原生的装饰器,用的话,只能改参数,那样的话不通用
class Home(View):
@method_decorator(login_auth)
def get(self,request):
pass
def post(self,request):
pass
#3,通过dispatch,给所有的方法添加装饰器
class Home(View):
@method_decorator(login_auth)
def dispatch(self,request,*args,**kwargs)
super().dispatch(request,*args,**kwargs)
def get(self,request):
pass
def post(self,request):
pass
django中间件
什么是中间件?
官方的说法,中间件是一个用来处理Django请求和响应的框架级别的钩子,他是一个轻量、低级别的插件系统。用于全局范围内改变Django的输入和输出。每个中间组件都负责一些特定功能
直白的说,中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会请求的特定的时间去执行这些方法
中间件能干嘛?
控制用户访问频率,全局登录校验,用户访问白名单,黑名单等
自定义中间件
中间件可以定义五个方法分别是:
process_request
process_request(self,request)
#request只有一个参数,就是request,这个request和视图函数中的request是一样的(在交给后面的路由之前,可以对这个request对象进行一些列的操作)
由于request对象是一样的,所以我们可以对request对象进行添加变量值,从而使后面的视图函数获得设置的变量值
它的返回值可以是None也可以是HttpResponse对象(比如手动设置),返回值是None的话,按正常流程继续走,交给下一个中间件,如果是response对象,Django不执行视图函数,而将相应对象返回给浏览器
#process_request总结
1.在执行视图函数之前执行
2.配置对个中间件的时候,按照MIDDLEWARE的祖册顺序,也就是列表的索引依次执行
3.不同中间件传递的request都是同一个对象
process_view
process_view(self,request,view_func,view_args,view_kwargs)
#在视图函数执行前调用process_view方法,如果在这里返回了一个HttpResponse对象,就不会执行后面的视图函数,直接倒叙执行process_response,返回给浏览器
process_template_response
process_template_response(self,request,response)
#必须返回response,不然[ two.process_template_response didn't return an HttpResponse object. It returned None instead.]
执行顺序是在视图函数执行完之后,立即执行,但是他有一个前提,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。
process_exception
process_exception(self,request,exception)
#只有在视图函数出现了异常才执行,他可以是None或者是HttpResponse对象,如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
process_response
process_response(self,request,response)
#一定要返回response,不然会报错,[ 'NoneType' object has no attribute 'get']
response是视图函数返回的HttpResponse对象(也就是说这是Django后台处理完之后给出的一个具体的视图)。该方法的返回值,必须有,且必须是HttpResponse对象!!!!!
如果返回其他对象,浏览器不会拿到Django后台给他的视图,而是我们中间件返回的对象
总结执行顺序
process_request(正序) --> process_view(正序) --> process_exception(倒序) -->process_template_response(倒序) -->process_response(倒序)
csrf(跨站请求伪造)
在中间件的列表中有一个csrf的中间件,如果没有注释的情况下 且没有设置相关的csrf标签就会出现:Forbidden (403)
钓鱼网站:银行转账的路径,你是否也可以拿到,然后你做一个跟银行一模一样的页面,也超银行的借口提交数据,当用户在钓鱼网站输入对方账户名和转账金额之后,点击发送。其实内部是将对方账户换成了钓鱼网站的造假人员的账户。造成你转账转错账户的情况
如何避免上面的情况?
这时候csrf就提现作用了,设置csrf_token,就会生成一个随机字符串,将字符串进行比对校验就可以解决上述的问题,大致有以下2种方法设置csrf_token
方法一
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆页面</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="" method="post">
{% csrf_token %} <!--设置一个个隐藏的标签,里面存放一个随机产生的字符串(页面刷新也会刷新)-->
<label for="">username:<input type="text" name="username"></label>
<label for="">password:<input type="password" name="password"></label>
<input type="submit" value="submit">
</form>
</body>
</html>
方法二,利用ajax
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆页面</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="" method="post">
{% csrf_token %} <!--设置一个个隐藏的标签,里面存放一个随机产生的字符串(页面刷新也会刷新)-->
<label for="">username:<input type="text" name="username"></label>
<label for="">password:<input type="password" name="password"></label>
<input type="submit" value="submit">
</form>
<script>
$('button').click(function () {
$.ajax({
url:'',
type:'post',
data:{'name':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()},
success:function (data) {
console.log(data)
}
})
})
</script>
</body>
</html>
设置是否用csrf中间件
from django.views.decorators.csrf import csrf_exempt,csrf_protect #csrd_exempt就是不使用,csrf_protect就是使用(中间件列表中没有注释,默认所有视图都使用csrf校验)
#FBV使用方法
@csrf_exempt #局部禁用
def index1(request):
return HttpResponse('ok')
@csrf_protect #局部使用
def index2(request):
return HttpResponse('ok')
#CBV比较特殊
csrf_protect 跟正常的CBV装饰器一样 三种都可以(就是上面添加装饰的三种方法)
csrf_exempt 只能有下面两种方式
@method_decorator(csrf_exempt,name='dispatch') # 第一种
class Index3(View):
# @method_decorator(csrf_exempt) # 第二种
def dispatch(self, request, *args, **kwargs):
super().dispatch(request,*args,**kwargs)
其实都是给dispatch加,也就是要作用就作用所有方法,而不能是单一方法
Auth认证模块
什么是Auth模块
Auth模块是Django自带的用户认证模块:
我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,这还真是个麻烦的事情呢。
Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。
auth模块的常用方法
from django.contrib import auth #先导入模块
authenticate()
提供了用户认证功能,验证用户名及密码是否正确,一般需要username,password两个关键字参数
如果验证成功,返回一个User对象
用法
user = authenticate(username='username',password='password')
login(HttpRequest,user)
该函数接收一个HttpRequest对象,以及一个经过认证的User对象。
该函数实现用户登录的功能,本质上是会在后端生成该用户相关的session数据
用法:
from django.contrib.auth import authticate,login
def my_view(request):
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username,password=password)
if user is not None:
login(request,user) #会生成一个session,一旦记录了,可以在任意的地方通过request.user获取到当前登录对象
# Redirect to a success page.
else:
# Return an 'invalid login' error message.
logout(request)
该函数接收一个HttpRequest对象,无返回值
当调用该函数时,当前请求的session信息会全部删除,该用户即时没有登录,使用该函数也不会报错
用法:
from django.contrib.auth import logout
def logout_view(requeset):
logout(request)
# Redirect to a success page.
is_authenticated()
用来判断当前请求是否通过了验证
用法:
def my_view(request):
if not request.user.is_authenticated():
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
login_required()
auth 给我们提供的一个装饰器工具,用来快捷的给某个视图添加登录校验
用法
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
...
如果没有登录,则会跳转到django默认的登录URL'/accounts/login/'并传递当前访问的url的绝对路径(登录成功后,会重定向到该路径)
如果需要自定义登录的URL,则需要在setting.py文件中通过LOGIN_URL进行修改
示例:
LOGIN_URL='/login/' # 这里配置成你项目登录页面的路由
create_user() (create_superuser()) 两者创建方法一样
auth 提供一个创建新用户的方法,需要提供必要参数(username,password)等
用法:
form django.contrib.auth.models import User
user = User.objects.create_user(username='用户名',password='密码',email='邮箱',...)
#超级用户相比普通用户,is_superuser和is_staff 是True
check_password(password)
auth提供的一个检查密码是否正确地方法,需要提供当前请求用户的密码
密码正确返回True,否则返回False
用法
ok = user.check_password('密码')
set_password(password)
auth提供的一个修改密码的方法,接收要设置的新密码作为参数
注意:设置完一定要调用用户对象的save方法!!!!!!!!!!
用法
user.set_password(password='')
user.save()
user对象的属性
User对象属性:username,password
is_staff:用户是否拥有网站的管理权限
is_active:是否允许用户登录,设置为False,可以在不删除用户的前提下禁止用户登录
扩展默认的auth user表
如果想要添加自定义的字段,我们可以扩展user表
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
phone = models.CharField(max_length=11,null=True,unique=True)
注意,如果按上面的方式拓展了内置的auth_user表之后,一定要在settings.py中告诉Django,我们现在使用新定义的UserInfo表来做用户认证
写法:
AUTH_USER_MODEL = 'app名.UserInfo'
注意:
如果一旦指定了新的认证认证系统所用的表,我们就需要重新在数据库中创建表,而且不能再继续使用原来默认的auth_user表了
方法二
创建一张表,一对一关系绑定
class Userinfo(models.Model):
phone = models.CharField(max_length=32)
avatar = models.CharField(max_length=32)
ab = models.OneToOneField(to=User)