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)

 

posted @ 2019-06-21 17:29  纵横捭阖行  阅读(178)  评论(0编辑  收藏  举报