基于session实现登陆javascript
def login(request): if request.method == 'POST': username = request.POST.get('username') pwd = request.POST.get('password') if username=='jason' and pwd=='123': request.session['name'] = 'jason' # 这一步是添加session return redirect('/home/') return render(request,'login.html')
若是说后面咱们遇到了多个页面这些操做,都要实现校验,那么就得用到了装饰器,给类添加装饰器怎么添加?css
装饰器html
from functools import wraps def login_auth(func): @wraps(func) def inner(request,*args,**kwargs): if request.session.get('name'): return func(request,*args,**kwargs) return redirect('/login') return inner
类添加装饰器前端
# 给CBV添加装饰器的方法 ''' 1.第一种直接再类上面,必须指定name参数 2.直接再类里面的函数添加 3.重写dispatch方法 4.前端action里面修改路由 ''' # @method_decorator(login_auth,name='get') # 第一种 class Myhome(View): @method_decorator(login_auth) # 第三种 只要是总路由里面的均可以被装饰 def dispatch(self, request, *args, **kwargs): super().dispatch(request,*args,**kwargs) # @method_decorator(login_auth) # 第二种 def get(self,request): return HttpResponse('get') def post(self,request): return HttpResponse('post')
官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每一个中间件组件都负责作一些特定的功能。java
可是因为其影响的是全局,因此须要谨慎使用,使用不当会影响性能。jquery
说的直白一点中间件是帮助咱们在视图函数执行以前和执行以后均可以作一些额外的操做,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。数据库
咱们一直都在使用中间件,只是没有注意到而已,打开Django项目的Settings.py文件,看到下图的MIDDLEWARE配置项。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', ]
MIDDLEWARE配置项是一个列表(列表是有序的),列表中是一个个字符串,这些字符串实际上是一个个类,也就是一个个中间件。django默认有七个中间件,可是django暴露给用户能够自定义中间件而且里面能够写五种方法bootstrap
请求来了以后会依次通过每个门户,才会到urls.py后端
查看具体方法
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
ps:
1.请求来的时候会依次执行每个中间件里面的process_request方法,若是没有直接经过
2.响应走的时候会依次执行每个中间件里面的process_response方法,若是没有依次经过(后面在补充,有点小坑)
中间件能够定义五个方法,分别是:(主要的是process_request和process_response)
以上方法的返回值能够是None或一个HttpResponse对象,若是是None,则继续按照django定义的规则向后继续执行,若是是HttpResponse对象,则直接将该对象返回给用户。
新建一个任意名字的文件夹,里面新建一个任意名字的文件夹
中间件本质就是含有5个能够修改的内置方法的类,因此自定义的时候须要作的就是先继承一个Django提供的中间件混合父类--MiddlewareMixin
而后记得去settings中配置中间件
请求来了以后会依次往下走
请求走的时候也是从下往上依次执行,可是咱们要知道的是,django中说你在当前这个中间件中的process_request中返回了HttpResponse的话,会直接走这个中间件的response方法,直接按照这个中间件的顺序从下往上返回信息。
具体信息查看
注意:若是你的自定义process_response不返回一个return response的话,会直接报错
报错信息是
在自定义的中间件中process_response返回了response
process_request有一个参数,就是request,这个request和视图函数中的request是同样的(在交给Django后面的路由以前,对这个request对象能够进行一系列的操做)。
因为request对象是同样的,因此咱们能够对request对象进行一系列的操做,包括request.变量名=变量值,这样的操做,咱们能够在后续的视图函数中经过相同的方式便可获取到咱们在中间件中设置的值。
它的返回值能够是None也能够是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,若是是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。
咱们来看看多个中间件时,Django是如何执行其中的process_request方法的。
class Mymiddlewera(MiddlewareMixin): def process_request(self,request): print('我是app02中mymiddlewera中第一个自定义的中间件方法请求方法') class Mymiddlewera2(MiddlewareMixin): def process_request(self,request): print('我是app02中mymiddlewera中第二个自定义的中间件方法请求方法')
settings中配置
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', 'app02.mymiddlewera.middle.Mymiddlewera', # 自定义中间件1 'app02.mymiddlewera.middle.Mymiddlewera2' # 自定义中间件2 ]
经过终端打印,咱们发现中间件是自上而下依次执行
而后咱们调换一下位置
在打印一下两个自定义中间件中process_request方法中的request参数,会发现它们是同一个对象。
总结:
由此总结一下:
多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最早执行。
定义process_response方法时,必须给方法传入两个形参,request和response。request就是上述例子中同样的对象,response是视图函数返回的HttpResponse对象(也就是说这是Django后台处理完以后给出一个的一个具体的视图)。该方法的返回值(必需要有返回值)也必须是HttpResponse对象。若是不返回response而返回其余对象,则浏览器不会拿到Django后台给他的视图
经过咱们上面的代码和图片演示,咱们直接进行总结
总结:
process_response方法是在视图函数以后执行的,而且顺序是从下往上依次执行。
多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最早执行。
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方法,最后返回给浏览器
class Mymiddlewera(MiddlewareMixin): def process_request(self,request): print('我是app02中mymiddlewera中第一个自定义的中间件方法请求方法') print('111',request) # return HttpResponse('好想好好的睡个一晚上直到天亮') def process_response(self,requset,response): print('我是app02中mymiddlewera中第一个自定义的中间件方法响应方法') return response # 必须将response接收到的数据返回,否则报错 def process_view(self,request,view_func,view_args,view_kwargs): print('111,你说啥就是啥吧') print(view_func) print(view_args) print(view_kwargs)
终端打印结果
process_view方法是在Django路由系统以后,视图系统以前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的
process_exception(self, request, exception)
该方法两个参数:
一个HttpRequest对象
一个exception是视图函数异常产生的Exception对象。
这个方法只有在视图函数中出现异常了才执行,它返回的值能够是一个None也能够是一个HttpResponse对象。若是是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,不然将默认处理异常。若是返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
class Mymiddlewera(MiddlewareMixin): def process_request(self,request): print('我是app02中mymiddlewera中第一个自定义的中间件方法请求方法') print('111',request) # return HttpResponse('好想好好的睡个一晚上直到天亮') def process_response(self,requset,response): print('我是app02中mymiddlewera中第一个自定义的中间件方法响应方法') return response # 必须将response接收到的数据返回,否则报错 def process_view(self,request,view_func,view_args,view_kwargs): print('111,你说啥就是啥吧') print(view_func) print(view_args) print(view_kwargs) def process_exception(self,request,exception): print('222,你可真烦人啊!') print(exception)
process_template_response(self, request, response)
它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。
process_template_response是在视图函数执行完成后当即执行,可是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者代表该对象是一个TemplateResponse对象或等价方法)。
class Mymiddlewera(MiddlewareMixin): def process_request(self,request): print('我是app02中mymiddlewera中第一个自定义的中间件方法请求方法') print('111',request) # return HttpResponse('好想好好的睡个一晚上直到天亮') def process_response(self,requset,response): print('我是app02中mymiddlewera中第一个自定义的中间件方法响应方法') return response # 必须将response接收到的数据返回,否则报错 def process_view(self,request,view_func,view_args,view_kwargs): print('111,你说啥就是啥吧') print(view_func) print(view_args) print(view_kwargs) def process_exception(self,request,exception): print('222,你可真烦人啊!') print(exception) def process_template_response(self,request,response): print('我是app02中的mymiddlewera中第一个自定义的render方法') return response
views.py
def index(request): print('我是index,哈哈哈哈') # print(request.method) def render(): print('567890') # return 123 return HttpResponse('haodezhidaole ') obj = HttpResponse('ok') # print(1111) obj.render=render # 这一步实际上触发了process return obj
视图函数执行完以后,当即执行了中间件的process_template_response方法,顺序是倒序,先执行MD1的,在执行MD2的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法。
总结:
process_request:请求来的时候从下往上依次执行每个中间件里面的process_request
process_response:响应走的时候会从下往上依次执行执行每个中间件的process_response方法
process_view:路由匹配成功,执行视图函数以前自动触发(顺序是从上往下依次执行),view_func是执行视图函数的名字
process_exception:当视图函数出现报错,会自动触发,顺序是依次往下往上执行
process_template_response:当你返回对象的时候有一个render()方法的时候会触发,执行顺序从下往上依次执行
***************
django中渐渐暗可以帮我实现 网站全局的身份验证,黑名单,白名单,访问频率限制,反爬相关等等
》》》:django用来帮你作全局相关的功能校验
RBAC:基于角色的权限管理(不一样的客户能够给出不一样的访问权限)
因此后面只要是涉及到了全局相关,咱们就能够直接再中间件这里进行操做,好比说去数据库中进行校验这个用户权限,而后只对他开放特定的功能块儿!
钓鱼网站就是建一个和正常的网站如出一辙的网站,而后用户在输入的时候调的也是正常网站的接口去处理,因此用户的钱会扣掉,可是并无转给指定的人,其实就是建了一个和正常网站如出一辙的东西,而后偷偷的在转给目标用户那里,偷偷的将input框当前的name去掉,而后用了一个hidden隐藏起来,在隐藏起来的input框中给一个默认的value,具体示例以下
模拟钓鱼网站示例
正常网站 views.py
def transfer(request): if request.method == 'POST': username = request.POST.get('name') money = request.POST.get('money') others = request.POST.get('others') print('%s 给 %s 转了 %s块钱'%(username,others,money)) return render(request,'transfer.html')
正常网站transfer.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </head> <body> <h1>正经网站</h1> <form action="" method="post"> <p>name:<input type="text" name="name"></p> <p>money:<input type="text" name="money"></p> <p>others:<input type="text" name="others"></p> <input type="submit"> </form> </body> </html>
钓鱼网站 transfer.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </head> <body> <h1>钓鱼网站</h1> <form action="http://127.0.0.1:8000/transfer" method="post"> <p>name:<input type="text" name="name"></p> <p>money:<input type="text" name="money"></p> <p>others: <input type="text" > <input type="hidden" name="others" value="mcc" style="display: none" > </p> <input type="submit"> </form> </body> </html>
这样就是最开始的网络诈骗ヽ(*。>Д<)o゜ヽ(*。>Д<)o゜
那咱们学习了之后,如何保证咱们的网站的安全呢?🤭🤭🤭,这个时候咱们就想到了咱们刚开始学习让注册掉的那个
django.middleware.csrf.CsrfViewMiddleware
中间件,他就是用来作校验的,他会每次都会在页面动态刷新生成一个value,而后每次用key值来比对这个value,经过了才会作下一步操做,否则的话就会直接拒绝这个请求,写法也很简单
咱们直接在form表单中写{% csrf token%},这个时候,django的中间件就会自动的帮咱们去校验,他会每次都动态的生成一个验证码,只要页面刷新验证码就会不一样,具体以下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </head> <body> <h1>正经网站</h1> <form action="" method="post"> {% csrf_token %} <p>name:<input type="text" name="name"></p> <p>money:<input type="text" name="money"></p> <p>others:<input type="text" name="others"></p> <input type="submit"> </form> </body> </html>
这样的话,钓鱼网站怎么也访问不了
让你再骗人,😕😕😕
具体作法看图
每次这个value都会刷新,这样的话钓鱼网站怎么也访问不了
这个中间件这么神奇,可是咱们中间也有一些函数不想校验,具体作法以下
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_exempt def index(request): pass
@csrf_protect def login(request): pass
from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt,csrf_protect
三种方法均可以用,和正常的CBV装饰器方法同样
给CBV取消单个校验(csrf-exempt)
不能给单独的视图函数添加,只有dispatch能够,是由于给全局加的
直接给类加的,就要指定name='dispatch'
总结:其实都是给dispatch加,类就是一个路由,里面不能够单独写, --所有都要加到全局才能够
@method_decorator(csrf_exempt,name='dispatch') # 第一种 class Csrf_Token(View): @method_decorator(csrf_exempt) # 第二种 def dispatch(self,request,*args,**kwargs): res = super().dispatch(request,*args,**kwargs) return res @method_decorator(csrf_exempt) # 这里这么写不行!!! def get(self,request): pass def post(self,request): pass
Auth模块是Django自带的用户认证模块:
咱们在开发一个网站的时候,无可避免的须要设计实现网站的用户系统。此时咱们须要实现包括用户注册、用户登陆、用户认证、注销、修改密码等功能,这还真是个麻烦的事情呢。
Django做为一个完美主义者的终极框架,固然也会想到用户的这些痛点。它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。
from django.contrib import auth
提供了用户认证功能,即验证用户名以及密码是否正确,通常须要username 、password两个关键字参数。
若是认证成功(用户名和密码正确有效),便会返回一个 User 对象。
authenticate()会在该 User 对象上设置一个属性来标识后端已经认证了该用户,且该信息在后续的登陆过程当中是须要的。
用法:
user = authenticate(username='usernamer',password='password')
该函数接受一个HttpRequest对象,以及一个通过认证的User对象。
该函数实现一个用户登陆的功能。它本质上会在后端为该用户生成相关session数据。
用法:
from django.contrib.auth import authenticate, login def my_view(request): username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username, password=password) if user is not None: login(request, user) # Redirect to a success page. ... else: # Return an 'invalid login' error message. ...
该函数接受一个HttpRequest对象,无返回值。
当调用该函数时,当前请求的session信息会所有清除。该用户即便没有登陆,使用该函数也不会报错。
用法:
from django.contrib.auth import logout def logout_view(request): logout(request) # Redirect to a success page.
用来判断当前请求是否经过了认证。
def my_view(request): if not request.user.is_authenticated(): return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
auth 给咱们提供的一个装饰器工具,用来快捷的给某个视图添加登陆校验。
用法:
from django.contrib.auth.decorators import login_required @login_required def my_view(request): ...
若用户没有登陆,则会跳转到django默认的 登陆URL '/accounts/login/ ' 并传递当前访问url的绝对路径 (登录成功后,会重定向到该路径)。
若是须要自定义登陆的URL,则须要在settings.py文件中经过LOGIN_URL进行修改。
示例:
LOGIN_URL = '/login/' # 这里配置成你项目登陆页面的路由
auth 提供的一个建立新用户的方法,须要提供必要参数(username、password)等。
用法:
from django.contrib.auth.models import User user = User.objects.create_user(username='用户名',password='密码',email='邮箱',...)
auth 提供的一个建立新的超级用户的方法,须要提供必要参数(username、password)等。
用法:
from django.contrib.auth.models import User user = User.objects.create_superuser(username='用户名',password='密码',email='邮箱',...)
auth 提供的一个检查密码是否正确的方法,须要提供当前请求用户的密码。
密码正确返回True,不然返回False。
用法:
ok = user.check_password('密码')
auth 提供的一个修改密码的方法,接收 要设置的新密码 做为参数。
注意:设置完必定要调用用户对象的save方法!!!
用法:
user.set_password(password='') user.save()
User对象属性:username, password
is_staff : 用户是否拥有网站的管理权限.
is_active : 是否容许用户登陆, 设置为 False,能够在不删除用户的前提下禁止用户登陆。
这内置的认证系统这么好用,可是auth_user表字段都是固定的那几个,我在项目中无法拿来直接使用啊!
好比,我想要加一个存储用户手机号的字段,怎么办?
聪明的你可能会想到新建另一张表而后经过一对一和内置的auth_user表关联,这样虽然能知足要求可是有没有更好的实现方式呢?
答案是固然有了。
咱们能够经过继承内置的 AbstractUser 类,来定义一个本身的Model类。
这样既能根据项目需求灵活的设计用户表,又能使用Django强大的认证系统了。
from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): """ 用户信息表 """ nid = models.AutoField(primary_key=True) phone = models.CharField(max_length=11, null=True, unique=True) def __str__(self): return self.username
注意:
按上面的方式扩展了内置的auth_user表以后,必定要在settings.py中告诉Django,我如今使用我新定义的UserInfo表来作用户认证。写法以下:
# 引用Django自带的User表,继承使用时须要设置 AUTH_USER_MODEL = "app名.UserInfo"
再次注意:
一旦咱们指定了新的认证系统所使用的表,咱们就须要从新在数据库中建立该表,而不能继续使用原来默认的auth_user表了。