12.5 csrf校驗和auth模塊

1.基於django中間件的拷貝思想

需求:實現三種通知功能
#方式一:
#notify.py
def send_email(content):
    print('郵箱通知:%s'% content)

def send_msg(content):
    print('短信通知:%s'% content)

def send_wechat(content):
    print('微信通知:%s'% content)
    
#start.py
from first.notify import *

def send_all(content):
    send_msg(content)
    send_email(content)
    send_wechat(content)

if __name__ == '__main__':
    send_all('後天是週末')
    
#方式二:
#lib文件夾
#bbb.py
name='from bbb'

#aaa.py
import importlib
res='lib.bbb'
#利用字符串形式導入模塊
md=importlib.import_module(res)  #這句至關於 from lib import bbb
print(md)    #該模塊字符串最小單位只能到文件名

#settings.py
NOTIFY_LIST=[
    'notify.email.Email',
    'notify.msg.Msg',
    'notify.qq.Qq',
    'notify.WeChat.WeChat',
]
#start.py
from notify import *
send_all('週末了,哈哈哈哈')

#notify 包文件
#email.py
class Email(object):
    def __init__(self):
        pass

    def send(self,content):
        print('郵件通知:%s'%content)
        
#msg.py
class Msg(object):
    def __init__(self):
        pass

    def send(self, content):
        print('短信通知:%s' % content)
        
#qq.py
class Qq(object):
    def __init__(self):
        pass

    def send(self, content):
        print('qq通知:%s' % content)
        
#wechat.py
class WeChat(object):
    def __init__(self):
        pass

    def send(self, content):
        print('微信通知:%s' % content)        
        
#__init__.py
import settings
import importlib

def send_all(content):
    for path in settings.NOTIFY_LIST:  #拿到一個個的路徑字符串 'notify.email.Email'
        module_path,cls_name=path.rsplit('.',maxsplit=1)  
        #字符串'notify.email'  類cls_name='Email'
        md=importlib.import_module(module_path)  #from notify import email
        cls=getattr(md,cls_name)   #獲取到文件夾中類的名字
        obj=cls()  #產生一個個類對象
        obj.send(content)  #鴨子類型

2.跨站請求僞造csrf

  • 如何實現釣魚網站html

    • 你在寫form表單的時候 讓用戶填寫的帳戶input並無name屬性,是你本身在內部偷偷隱藏了一個具備name屬性的input框,而且value值是你本身的帳戶,而後將該標籤隱藏了
  • 模擬該現象的產生 建立兩個django項目python

#正經網站
#transfer.py
def transfer(request):
    if request.method=='POST':
        username=request.POST.get('username')
        target_user=request.POST.get('target_user')
        money=request.POST.get('money')
        print('%s 給 %s 轉了 %s錢'%(username,target_user,money))

    return render(request,'transfer.html')
#transfer.html
<p>這是正經網站</p>
<form action="" method="post">
    <p>username:<input type="text" name="username"></p>
    <p>target_account:<input type="text" name="target_user"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
    
    
#釣魚網站
#transfer.py
def transfer(request):
    return render(request,'transfer.html')

#transfer.html
<p>這是假冒的網站</p>
<form action="http://127.0.0.1:8000/transfer/" method="post">
    <p>username:<input type="text" name="username"></p>
    <p>target_account:
        <input type="text">
        <input type="text" name="target_user" value="ldd" style="display: none"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
  • 如何解決釣魚網站這種問題:只處理本網站提供的數據
  • 那麼如何判斷當前請求是本網站發出的呢?
    • 解決方法:網站在返回給用戶一個form表單的時候 會自動在該表單隱藏一個input框,這個框

的value是一個隨機字符串 可是網站可以記住每個瀏覽器發送的隨機字符串ajax

之後在寫form表單的時候 只須要在表單中寫一個{% csrf_token %}
<p>這是正經網站</p>
<form action="" method="post">
    {% csrf_token %}
    <p>username:<input type="text" name="username"></p>
    <p>target_account:<input type="text" name="target_user"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
  • 爲了防止釣魚網站惡意攔截,正常網站都只要接收到post請求,都會作csrf校驗

3.ajax的post請求如何用csrf解決

  • 方式一:較爲繁瑣
    • 先在頁面任意位置上書寫{% csrf_token %}
    • 而後在發送ajax請求的時候 經過標籤查找獲取隨機字符串,添加到data自定義對象便可
  • 方式二:較爲簡單
  • 方式三:官網提供的文件 最通用的一種方式,用於先後端分離
    • 直接新建js文件,放在static文件夾裏,記得settings裏面配一下。拷貝代碼 導入便可
    • 不須要作任何的csrf相關的代碼書寫
{% csrf_token %}
<button id="d1">發送ajax</button>

<script src="/static/setup.js"></script>  //js文件相關
<script>
    $('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            // 第一種
            data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},
            // 第二種
            data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},
            // 第三種  利用腳本文件
            data:{'username':'jason'},
            success:function (data) {
                alert(data)
            }
        })
    })
</script>
靜態文件夾裏的js文件:
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

將這些代碼的文件配置到你的Django項目的靜態文件中,在html頁面上經過導入該文件便可自動幫咱們解決ajax提交post數據時校驗csrf_token的問題,(導入該配置文件以前,須要先導入jQuery,由於這個配置文件內的內容是基於jQuery來實現的)django

4.csrf相關的裝飾器

from django.views.decorators.csrf import csrf_exempt,csrf_protect
# @csrf_exempt  # 不校驗 csrf
def index(request):
    return HttpResponse('index')


@csrf_protect  # 校驗
def login(request):
    return HttpResponse('login')
  • 這兩個裝飾器在CBV上有何異同
# @method_decorator(csrf_exempt,name='post')  # csrf_exempt不支持該方法
@method_decorator(csrf_exempt,name='dispatch')  # csrf_exempt
class MyIndex(views.View):
    # @method_decorator(csrf_exempt)  # 能夠
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request,*args,**kwargs)
    def get(self,request):
        return render(request,'transfer.html')
    # @method_decorator(csrf_exempt,name='post')  # csrf_exempt不支持該方法
    def post(self,request):
        return HttpResponse('OK')		
    # csrf_exempt這個裝飾器只能給dispatch裝才能生效
    
    """
	csrf_protect方式全均可以  跟你普通的裝飾器裝飾CBV一致
	"""
    # @method_decorator(csrf_protect,name='post')  # 能夠
    class MyIndex(views.View):
        @method_decorator(csrf_protect)
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request,*args,**kwargs)
        def get(self,request):
            return render(request,'transfer.html')
        # @method_decorator(csrf_protect)  # 能夠
        def post(self,request):
            return HttpResponse('OK')

5.django源碼剖析

  • django有兩個配置文件,一個是暴露給用戶能夠配置的,一個是內部全局的(用戶配置了就用用戶的,用戶沒有配置就用本身的)
  • 先加載全局配置 給對象設值;而後加載局部配置 再給對象設值;一旦有重複的項,後者覆蓋前者。
from django.conf import global_settings
from django.conf import settings

6.auth模塊

  • 使用auth模塊的時候,要用就用它的全套後端

  • 如何建立超級用戶(root)瀏覽器

python manage.py createsuperuser
  • auth模塊經常使用方法:
1.建立用戶
from django.contrib.auth.models import User
# User.objects.create(username=username,password=password)  # 不可用  密碼不是加密的
# User.objects.create_user(username=username,password=password)  # 建立普通用戶    密碼自動加密
#User.objects.create_superuser(username=username,password=password,email='123@qq.com')  # 建立超級用戶   須要郵箱數據
2.校驗用戶名和密碼是否正確
from django.contrib import auth
user_obj = auth.authenticate(request,username=username,password=password)
# 必須傳用戶名和密碼兩個參數缺一不能
3.保存用戶登陸狀態
auth.login(request,user_obj)
# 只要這句話執行了 後面在任意位置 只要你能拿到request你就能夠經過request.user獲取到當前登陸的用戶對象
4.判斷當前用戶是否登陸
request.user.is_authenticated()
5.校驗原密碼是否正確
request.user.check_password(old_password)
6.修改密碼
request.user.set_password(new_password)
request.user.save()  # 千萬不要忘了
7.註銷
auth.logout(request)
8.校驗用戶是否登陸裝飾器
from django.contrib.auth.decorators import login_required
局部配置
@login_required(login_url='/login/')
def index(request):
    pass
全局配置
settings配置文件中 直接配置
LOGIN_URL = '/login/'
@login_required
def index(request):
    pass
# 若是全局配置了 局部也配置  以局部的爲準

7.擴展auth_user表字段

方式1
    利用一對一外鍵字段關係
    class UserDetail(models.Model):
        phone = models.BigIntegerField()
        user = models.OneToOneField(to='User')

    方式2	
    利用繼承關係  
    from django.contrib.auth.models import AbstractUser
    class Userinfo(AbstractUser):
        phone = models.BigIntegerField()
        register_time = models.DateField(auto_now_add=True)

        # 必定要注意 還須要去配置文件中配置
        AUTH_USER_MODEL = 'app01.Userinfo'  # 應用名.表名
        #以前全部的auth模塊功能也全適用於擴展好的表
相關文章
相關標籤/搜索