Djangoはミドルウェア詳細CSRF、ミドルウェアのアイデアを呼び出して、Djangoの設定ソースコード解析、Djangoの認証モジュール

使用Djangoは彼らのイデオロギー関数呼び出しミドルウェアを完了します

コールミドルウェアは唯一あなたがミドルウェアを使用しない場合は、設定ファイルに追加する必要があり、コンフィギュレーションファイル内の唯一の対応する文字列は、実行呼び出し、そのようなコードは非常に簡単に行うことではなく、コメントアウトすることができます?ここでは、Djangoのミドルウェアを呼び出すために思考を使用し、実装され、その機能は同じミドルウェアによって呼び出されます。

機能要件

想定の機能が実装さ:情報の塊が、我々は1つのキーだけを送ることができる必要書き込まれた情報を必要とし、我々は、通知のいくつかの種類を必要としない場合は、マイクロ文字でメールで三つの方法を送ったSMSは、構成ファイルでのみ必要となります我々はそれをコメントアウトすることができます。

importlibモジュールの紹介

ダイナミックインポートモジュールのimportlibは、満たされたドット列のファイルパスに基づいて分離することができる、対応するファイルへの道を取るために資格があります。どのように使用するには:

module_path = 'notify.msg'
md = importlib.import_module(module_path) #md就是notify文件夹下的msg文件

関数又はクラスのメソッドを定義するファイルを取得する必要があり、反射を使用することができた場合(オブジェクトとしてここファイル、すべてのオブジェクトです)

cls = getattr(md,cls_name)#将文件名作为对象右面填类的名字就能拿到对应的类

の機能を実現

1ビルド情報の各一方向伝送のために別のファイルのグループ図メッセージング、ライトとしてパッケージ。

各ファイルの通知として、対応する通知タイプを定義2:

class Msg:
    def __init__(self):
        pass

    # 发送信息前的准备

    def send(self, content):
        print(f'Msg通知:{content}')

次のように各ファイルの設定ファイルに追加3:

NOTIFY_LISTS = [
    'notify.email.Email',
    'notify.msg.Msg',
    'notify.qq.Qq',
    'notify.WeChat.WeChat'
]

4.検索とインスタンス化クラスが初期化して処理されます

import importlib
import settings
def send_all(content):
    for path in settings.NOTIFY_LISTS:
        module_path,cls_name = path.rsplit('.',maxsplit=1)
        module = importlib.import_module(module_path)
        cls = getattr(module,cls_name)
        obj = cls()
        obj.send(content)
        

パケット通話開始メッセージは、大量の機能を実現します

import os,sys
from notify import send_all


sys.path.append(os.path.dirname(__file__))

if __name__ == '__main__':
    send_all('现在测试通知')
    
Email通知:现在测试通知
Msg通知:现在测试通知
QQ通知:现在测试通知
WeChat通知:现在测试通知

したがって、基本的な機能を実現しています。

CSRFミドルウェア詳細

クロスサイトリクエストフォージェリ

全クロスサイトリクエストフォージェリ(CSRF)CSRF、ユーザーが現在ログインしているWebアプリケーションにハイジャック攻撃意図しない操作を実行します。クロスサイトスクリプティング(XSS)と比較すると、XSSは、ユーザーがサイトを指定した信頼関係を悪用し、CSRFは信頼にWebサイトのユーザーのWebブラウザを利用します。

CSRFなフィッシングサイト、フィッシングサイトの特定の漁業の方法として最も一般的なアプリケーション、:フィッシングサイトがまったく同じサイトを、通常のWebインターフェイスを偽造し、転送(入金)関数は、フォームはときに、ユーザーのログを提供するように変更することがフォーム通常のサイトのログインインタフェースは、ユーザーの支払いやその他の移転はアカウント各ユーザーが相手にお金を転送しますのでことを、あらかじめ定義されたアカウント(入力ボックスの名前と値)の下に隠れ、偽であります事前に定義されたアカウントにアクセスしてください。どのようにクロスサイトリクエストフォージェリ、それを解決するには?

サーバーの視点からアイデアは、サーバがフィッシングサイト、私は自分にあったページまたは他の誰かのページに要求を提出する特定できる場合は、ユーザー・アクセス・サーバの間にサービスとして偽装することができないということであるたびに、この問題を解決するために、サーバーへの転送要求を送信するためのページを終了します。Djangoのミドルウェアは、このアイデアにより、クロスサイトリクエストフォージェリの問題を解決することです。

ジャンゴCSRFミドルウェア

ユーザーは、サーバーへのアクセス権を持っている場合にはDjangoのCSRFミドルウェアジャンゴCSRFミドルウェア、ユーザーに与えるかどうかを確認していない場合には要求されたページは、ユーザーがユーザーのランダムな文字列をチェックするPOSTリクエストを送信し、ランダムな文字列を、運ぶ取得その後で直接403エラーを報告し、ポストの要求を提出するからユーザーを防ぎます。

<input type="hidden" name="csrfmiddlewaretoken" value="rJ47FeK9T55wavvVJGY6UxdM1kTMHhTqotGfaXjXIK8Ahz2Uvs02yR9T8bBn5q2D">

ポスト要求フォームと通常AJAXリクエストを形成する能力を実証し、両方のポスト要求にDjangocsrfミドルウェアの使用は異なり、次のように特定の用途があります。

フォームフォーム

私達はちょうどフォームform {%csrf_token%}に追加する必要があります。

<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">
</form>
<input type="hidden" name="csrfmiddlewaretoken" value="rJ47FeK9T55wavvVJGY6UxdM1kTMHhTqotGfaXjXIK8Ahz2Uvs02yR9T8bBn5q2D">           

アヤックス

AJAXミドルウェアラベルを追加するには、3つの方法があります。

次いで、最初のページ上の任意の位置に書き込み{%csrf_token%}、および要求AJAXを送信するときに、カスタムオブジェクトタグによって、すなわちランダムデータを追加取得する文字列を探して:
データ:{「ユーザ名」:「XXX」、「csrfmiddlewaretoken」 :$( '入力[NAME = "csrfmiddlewaretoken"]')のval()}、

第二の方法

データ:{ 'ユーザ名': 'XXX'、 'csrfmiddlewaretoken': '{{csrf_token}}}

三つの方法(正式には、このメソッドを使用することをお勧めします)

jsが新しいファイルには、上記のAJAXで導入することができ、次のコードにコピーされます。

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 csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader("X-CSRFToken", csrftoken);
    }
  }
});

インポート:

<script src="/static/setup.js"></script>

関連デコレータCSRF

関連デコレータCSRF我々のニーズに応じて表示する機能を加えたCSRFチェックを与えることができ、またはチェック機能CSRFビューを追加することではありません。

csrf_exempt

ビューのチェック機能に加えて、CSRFを与えてはいけません

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

csrf_protect

設定ファイルは、CSRFミドルウェアをコメントする必要があります機能の追加CSRFをチェックするビュー。

@csrf_protect  # 校验
def login(request):
    return HttpResponse('login')

CBVのプラスCSRFデコレータ

csrf_exempt

添加のみデコレータ方法は、第1のインポートmethod_decorator方法であり、その後、装飾方法はクラスで定義された発送発送方法で上記。@method_decorator(csrf_exempt)

# @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

プラス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')

Djangoの設定ソースコードの解析と模倣の使用

Djangoの設定は、ソースコード解析

Djangoは、2つの設定ファイルを持っているユーザーは、設定ファイルを見ることができ、他方が内部グローバルプロファイルであるユーザーならば、これら2つのプロファイルの実装では、ユーザープロファイルの設定ファイルを設定している場合ということです内部設定ファイルを使用するための設定なし設定ファイル。Djangoは、この機能は、それを実現する方法ですか?Djangoの設定ソースを見てみましょう。

内のプロファイルを見ます

from django.conf import settings#配置文件实例化出的一个类
from django.conf import global_settings#配置文件

、Singletonパターンを使用して検出設定:私たちは、最初の設定を入力します

クラス内のLazySettingsを入力します。

プロジェクトが始まった構成にManage.pyビュー:

ルックLazySettingsクラス

 def _setup(self, name=None):
        """
        Load the settings module pointed to by the environment variable. This
        is used the first time we need any settings at all, if the user has not
        previously configured the settings manually.
        """
        settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
        # os.environ是一个全局的大字典,而settings_module获取了key为ENVIRONMENT_VARIABLE的值,从manage.py中可以看出settings_module获取到的就是用户配置文件路径:项目名.settings
        if not settings_module:
            desc = ("setting %s" % name) if name else "settings"
            raise ImproperlyConfigured(
                "Requested %s, but settings are not configured. "
                "You must either define the environment variable %s "
                "or call settings.configure() before accessing settings."
                % (desc, ENVIRONMENT_VARIABLE))

        self._wrapped = Settings(settings_module)
        #settings路径传入了Settings,我们进Settings里面看看。
        
class Settings(object):
    def __init__(self, settings_module):
        # update this dict from global settings (but only for ALL_CAPS settings)
        for setting in dir(global_settings):#获取全局配置文件中所有变量名
            if setting.isupper():#只获取是大写的变量名,这就是为啥配置文件中所有的变量名都是大写的
                setattr(self, setting, getattr(global_settings, setting))#setattr将获取到global_settings的变量值添加到settings对象自己的属性中

        # store the settings module in case someone later cares
        self.SETTINGS_MODULE = settings_module#项目名.settings

        mod = importlib.import_module(self.SETTINGS_MODULE)
        #导入暴露给用户的配置文件,相当于from 用户名 import settings

        tuple_settings = (
            "INSTALLED_APPS",
            "TEMPLATE_DIRS",
            "LOCALE_PATHS",
        )
        
        
     self._explicit_settings = set()
        for setting in dir(mod):#获取用户配置文件中所有的变量名
            if setting.isupper():
                setting_value = getattr(mod, setting)#利用反射取出所有的变量值

                if (setting in tuple_settings and
                        not isinstance(setting_value, (list, tuple))):
                    raise ImproperlyConfigured("The %s setting must be a list or a tuple. " % setting)
                setattr(self, setting, setting_value)#将用户settings的属性和属性值写入settings对象中
                #到这里我们可以看到,实例化出的settings对象先将全局配置文件中的变量名和变量值写入,然后再将用户配置文件的变量名和变量值写入,这样如果用户配置文件配置了对应的变量名和变量值就会替换掉全局的,从而实现了如果用户配置了settings就用用户的,如果用户没有配置,就用全局的配置文件的功能。
                self._explicit_settings.add(setting)

        if not self.SECRET_KEY:
            raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
        

模倣の使用

実際には、模造模造ユーザープロファイル設定の使用使用するように設定されていない場合、ユーザーを使用するために設定した場合、内蔵されたこの機能。

私たちは、パッケージ__init__のグローバルコンフィギュレーションファイルに次のコードを記述する必要があります。

import importlib
from lib.conf import global_settings
import os

class Settings(object):
    def __init__(self):
        for name in dir(global_settings):
            if name.isupper():
                setattr(self,name,getattr(global_settings,name))
        # 获取暴露给用户的配置文件字符串路径
        module_path = os.environ.get('xxx')
        md = importlib.import_module(module_path)  # md = settings
        for name in dir(md):
            if name.isupper():
                k = name
                v = getattr(md,name)
                setattr(self,k,v)


settings = Settings()

認証モジュール

認証プロファイル

Djangoの認証モジュールが内蔵されているユーザ認証モジュール:

当社は、ユーザーのシステムを実現するためにウェブサイトを設計する必然的な必要性を、サイトを開発しています。この時点では、ユーザ登録、ユーザのログイン、ユーザ認証、ログオフ、変更のパスワードやその他の機能を含め、達成するために必要な、これは本当にまだ面倒なことです。

Djangoは究極の完璧主義者のためのフレームワークとして、当然のことながら、これらの痛みのポイントのユーザーを考えます。これは、ストアのユーザーデータへのAUTH_USERテーブルに強力なユーザ認証システム--auth、デフォルトを建てました。

共通モジュールの認証方法

機能 コード
ユーザーを作成します。 インポートユーザーdjango.contrib.auth.modelsから
User.objects.create_user(ユーザー名=ユーザー名、パスワード=パスワード)#は、通常のユーザーを作成し、パスワードが自動的に暗号化され
User.objects.create_superuser(ユーザー名=ユーザー名、パスワード=パスワード、電子メール=「123 @ qq.com「)#はスーパーユーザを作成します
ユーザー名とパスワードを検証 from django.contrib import auth
user_obj = auth.authenticate(request,username=username,password=password)
保存用户登录状态 auth.login(request,user_obj) 只要这句话执行了后面在任意位置 只要你能拿到request你就可以通过request.user获取到当前登录的用户对象
判断当前用户是否登录 request.user.is_authenticated()
校验原密码 request.user.check_password(old_password)返回bool值
修改密码 request.user.set_password(new_password)
request.user.save() 千万不要忘了save
注销 auth.logout(request)
校验用户登录装饰器 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
如果全局和局部都配置了以局部的为准

创建用户

create_user()

auth 提供的一个创建新用户的方法,需要提供必要参数(username、password)等,用户名和密码是必须提供的。

from django.contrib.auth.models import User
user = User.objects.create_user(username='用户名',password='密码',email='邮箱',...)

校验用户名和密码

提供了用户认证功能,即验证用户名以及密码是否正确,一般需要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.
    ...

判断当前用户是否登录

判断当前用户是否登录(发送的当前请求是否已经登录)

def my_view(request):
  if not request.user.is_authenticated():
    return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))

校验原密码

auth 提供的一个检查密码是否正确的方法,需要提供当前请求用户的密码。

密码正确返回True,否则返回False。

ok = user.check_password('密码')

修改密码

auth 提供的一个修改密码的方法,接收 要设置的新密码 作为参数。

注意:设置完一定要调用用户对象的save方法!!!

user.set_password(password='')
user.save()

注销

该函数接受一个HttpRequest对象,无返回值。

当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。

from django.contrib.auth import logout
   
def logout_view(request):
  logout(request)
  # Redirect to a success page.

校验用户登录状态装饰器

局部登录认证装饰器

@login_required(login_url='/login/')判断用户是否登录如果没有则直接跳转到登录页面

from django.contrib.auth.decorators import login_required
      
@login_required
def my_view(request):
  ...

如果需要自定义登录的URL,则需要在settings.py文件中通过LOGIN_URL进行修改。

示例:

LOGIN_URL = '/login/'  # 这里配置成你项目登录页面的路由

全局登录认证装饰器

在settings文件直接配置

LOGIN_URL = '/login/'#如果全局和局部都配置了以局部的为准

User对象属性(用户登录权限和管理权限)

User对象属性:username, password

is_staff : 用户是否拥有网站的管理权限.

is_active : 是否允许用户登录, 设置为 False,可以在不删除用户的前提下禁止用户登录。

扩展auth_user表字段

方式一

思路:再建一张表,使这张表和auth_user表是一对一的关系,这样可以实现对auth_user表字段的增加。

class UserDetail(models.Model):
    phone = models.BigIntegerField()
    user = models.OneToOneField(to='User')

方式二

思路:自定义一个类和原来的auth_user继承同一个基类,然后自定义类中的字段,这里需要说明的是在自定义类之前不能执行数据库迁移命令,定义好才能执行数据库迁移命令。另外,定义好类之后需要在配置文件中添加下面的配置。

#自定义类
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模块的功能都可以在你定义的表中使用。

おすすめ

転載: www.cnblogs.com/ghylpb/p/11992692.html