Django之csrf跨站请求伪造,auth认证模块
一.csrf跨站请求伪造:
用钓鱼网站模仿正规网站从而达到瞒天过海的操作,具体的操作如下:
首先,开一个正规网站服务器(为了模仿钓鱼,把csrf中间件关了):
视图:
def index(request): username = request.POST.get('username') money = request.POST.get('money') others = request.POST.get('others') return HttpResponse('%s 给 %s 成功转了 %s元!!! '%(username,others,money))
前端:
<h1>正规网址</h1> <form action="" method="post"> {# {% csrf_token %}#} <p>username:<input type="text" name="username"></p> <p>money:<input type="text" name="money"></p> <p>对方账户:<input type="text" name="others"></p> <input type="submit"> </form>
现在由于不小心进了一个与这个一模一样页面的网站,假设正规页面端口号8000,钓鱼8001:
视图:
def index(request): return render(request,'index.html')
前端(偷梁换柱):
<h1>钓鱼网站</h1> <form action="http://127.0.0.1:8000/index/" method="post"> <p>username:<input type="text" name="username"></p> <p>money:<input type="text" name="money"></p> <p>对方账户:<input type="text"></p> <input type="text" name="others" value="huangyan" style="display: none"> <input type="submit"> </form>
操作如下:
点完提交:
这时候出于正义,我们要杜绝此类恶行发生,掏出了csrf中间件:
'django.middleware.csrf.CsrfViewMiddleware',
此时,再提交试试:
看到这我们就放心了,那么回头想想这里面发生了什么?
<input type="hidden" name="csrfmiddlewaretoken" value="oEiTkGw3gB5zKUegA3OPvoBgbKVTp0BoAzbvluq0dFhd7NTUll0MrUJEZtCabShs">
此处有一个隐藏的键值对,包含了一个动态value值,每次提交都会更新,在比对时杜绝钓鱼网站的请求
那么自己要用,该怎么产生这个键值对来通过csrf中间件呢?
<h1>正经网址</h1> <form action="" method="post"> {% csrf_token %} <p>username:<input type="text" name="username"></p> <p>money:<input type="text" name="money"></p> <p>对方账户:<input type="text" name="others"></p> <input type="submit"> </form>
加上 {% csrf_token %} 就可以了,除了form表单,如果要传一些json字符串就要用到ajax,又该怎么办?
<button>ajax请求</button> <script> $('button').click(function () { $.ajax({ url:'', type:'post', data:{'name':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}, success:function (data) { console.log(data) } }) }) </script>
假如有部分的视图函数不想走csrf中间件的校验,可以加一个装饰器:
from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_exempt def home(request): return HttpResponse('home')
反过来,假如csrf中间件禁用了,现在想用它的校验:
@csrf_protect def login(request): return HttpResponse('login')
现在再来试试CBV:
路由:
url(r'^reg/',views.Reg.as_view()),
视图:
from django.views import View from django.utils.decorators import method_decorator # 装饰csrf装饰器的时候,只有这两种固定写法 @method_decorator(csrf_exempt,name='dispatch') # 第一种 class Reg(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')
二.auth认证模块
在数据库中创建一个表,往里面新建一条记录:
然后看到的表记录是这样的:
开始来登录一下:
from django.shortcuts import render,HttpResponse,redirect from django.contrib import auth def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # user = models.User.objects.filter(username=username,password=password).first() user = auth.authenticate(request,username=username,password=password) if user: auth.login(request,user) # 这一句执行完之后,其他的视图函数可以直接通过request.user获取到当前用户对象 # 这一句话就相当于操作session记录 return HttpResponse('登录成功') return render(request,'login.html') def index(request): print(request.user) print(request.user.username) print(request.user.password) return HttpResponse('index')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <form action="" method="post"> {% csrf_token %} <p>username:<input type="text" name="username"></p> <p>password:<input type="text" name="password"></p> <input type="submit"> </form> </body> </html>
session可以记住登录状态,登录后可以直接查看index视图,如果跳转之前要确认登录可以加装饰器:
在settings.py中配置一下,实现未登录跳转到登录页面:
LOGIN_URL = '/login/'
from django.contrib.auth.decorators import login_required
@login_required def home(request): return HttpResponse('home') @login_required def xxx(request): return HttpResponse('xxx')
接下来介绍一下注销:
def logout(request):
auth.logout(request)
# 相当于request.session.flush()
return HttpResponse('注销成功')
刚才是用run manage.py task工具添加记录的,现在我们来自己注册:
from django.shortcuts import render,HttpResponse,redirect from django.contrib import auth from django.contrib.auth.models import User def register(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') email = '111@qq.com' User.objects.create_user(username=username,password=password) # User.objects.create_superuser(username=username,password=password,email=email) # User.objects.create(username=username,password=password) # 不要用,密码是明文 return render(request,'register.html')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <form action="" method="post"> {% csrf_token %} <p>username:<input type="text" name="username"></p> <p>password:<input type="text" name="password"></p> <input type="submit"> </form> </body> </html>
我们现在来改一下密码:
@login_required def set_password(request): """ 123是用户原来的密码 456是用户修改的密码 这里为了偷懒没有做前后获取密码操作 """ print(request.user.check_password('123')) if request.user.check_password('123'): request.user.set_password('456') request.user.save() # 修改密码必须save保存.不然无效 return HttpResponse('ok')
如果你还想增加字段,那就要在models.py里进行操作了:
settings.py: # 告诉django不再使用默认的auth_user表,而是使用我自己的模型表 # AUTH_USER_MODEL = "app名.models里面对应的模型表名" AUTH_USER_MODEL = "app01.Userinfo" models.py: from django.db import models from django.contrib.auth.models import User,AbstractUser # Create your models here. # 一对一关联 class UserDetail(models.Model): phone = models.CharField(max_length=11) user = models.OneToOneField(to=User) # 第二种方式 class Userinfo(AbstractUser): phone = models.CharField(max_length=32) avatar = models.CharField(max_length=32)