1205 CSRFジャンゴクロス駅は、モジュールの認証を要求します

今日のコンテンツ

今日内容:
    
    基于配置文件的编程思想
    
    跨站请求伪造csrf
    
    django auth模块
    
    django settings源码剖析
    
    基于django settings源码实现自己项目配置文件插拔式设计

昨日のレビュー

cookie与session
        cookie与session发展史
            由于http协议是无状态的 所以我们需要发明一些能够保存用户的技术
        
        cookie
            保存在客户端浏览器上面的键值对(可以有多个)
            cookie是后端服务器控制与设值的 浏览器只是奉命行事
            浏览器也有权利拒绝写入cookie(一切需要登录认证的网站全都无法正常登录)
            
            如何查看浏览器上面的cookie
                application/COOKIES/信息
        
        session
            保存在服务端上的键值对(可以有多个)
            
        django如何操作cookie
            前提是需要用到HttpResponse对象
            obj = HttpResponse()
            obj1 = render()
            obj2 = redirect()
            
            设值cookie
                obj.set_cookie('k1','v1')
            获取cookie
                request.COOKIES.get('k1')
            设值失效时间
                obj.set_cookie('k1','v1',max_age=10)
                obj.set_cookie('k1','v1',expires=5)
                都以秒为单位expires针对IE浏览器
            删除cookie
                obj.delete_cookie('k1')
            
            基于cookie实现用户登录校验
                装饰器
                用户在没有登录之前如果访问了一个需要登录之后才能访问的页面
                那么会先跳转到登录页面 用户输入用户名和密码并正确的情况下
                再自动跳转到之前用户想要访问的页面
                    1.request.path_info
                    2.利用get请求携带参数的方法
    
    
        session操作
            django默认的session失效时间是14天,你也可以设置
            session是保存在服务端的 默认情况下 你的django需要先执行数据库迁移命令
            因为保存sesson数据的表需要先提前创建出来,如果不创建会报错(no such table:django_session)
            session不单单可以放在django_session表中  也可以放在任意能够作为数据库的地方
                文件
                内存
                缓存
                ...
                配置文件
                
            django的session表中的数据是针对浏览器的 同一个浏览器只会存一行数据
                
            
            设置session
                request.session['k1'] = 'v1'
                """
                    1.django内部自动调用算法 生成一个随机字符串
                    2.将随机字符串与设置的值保存到django_session表中(真正写入数据的操作是在django中间件里面的session相关中间件发生的)
                    3.将随机字符串返回给浏览器保存到cookie
                        sessionid:随机字符串
                """
            获取session
                request.session.get('k1')
                """
                    1.django内部会自动获取浏览器发送过来的cookie中的获取sessionid所对应的随机字符串
                    2.拿着随机字符串去django_session表中比对
                    3.如果有拿出数据放到request.session中供用户调用
                """
            删除session
                request.session.delete()
                request.session.flush()
            失效时间
                request.session.set_expiry()
                    1.数字(不能是0)   秒数
                    2.数字0    浏览器关闭自动失效
                    3.时间格式数据  datetime
                    4.不写    默认参考的是全局的失效时间
            
            基于session实现用户登录校验
    
    django中间件
        django中间件就类似于django的门户或者保安
        所有的请求和响应都必须经过中间件才能够正常通过
        并且在中间件中可以对请求和响应的数据进行处理
        django中间件在设计到一些全局方面的功能时 作用非常大
            1.网站全局的用户登录校验
            2.网站全局的访问频率校验
            3.网站全局的用户权限校验
            ...
            只要是全局的功能,你都应该第一个想到中间件
        
        django默认有七个中间件 每个中间件都有自己独立的功能 如果你想用 你直接注释掉即可
        django还支持用户自定义自己的中间件 并且暴露给用户五个可以自定义的方法
        
        前提
            1.只要是设计到处理前端业务逻辑的视图函数 都需要有形参request
            2.如果你想自定义中间件 你必须写一个类并且继承MiddlewareMixin
            3.一旦形参中reponse你就必须返回  因为response就是后端想要返回前端的数据
        五个方法
            需要掌握的
                1.process_request(self,request)  (******)
                    1.请求到来的时候 会按照配置文件注册的从上往下的顺序依次经过每一个中间件里面的该方法
                        如果中间件中没有定义该方法 直接跳过执行下一个
                    2.一旦该方法返回了一个HttpResponse对象 那么请求不再往后走 而是走到同级别的process_response依次返回
                
                2.process_response(self,request,response)
                    1.响应走的时候 会按照配置文件注册的从下往上的顺序依次经过每一个中间件里面的该方法
                        该方法默认必须返回response 如果你返回了自己的HttpResponse对象 那么用户收到的就是你的
            需要了解的
                3.process_view(self,request,view_name,*args,**kwargs)
                    1.路由匹配成功之后执行视图函数之前
                4.process_exception(self,request,response)
                    1.视图函数中出现错误的时候自动触发
                5.process_template_response(self,request,response)
                    1.返回的对象中含有render方法

設定ファイルのプログラミングのアイデアに基づいて、

importlibモジュール

文字列としてインポートモジュールを使用します

import importlib
res = 'lib.bbb'
md = importlib.import_moudle(res)
print(md)

IMG

簡単なコードの実装

首先定义一个配置路径列表
NOTIFY_LIST = [
    'notify.email.Email',
    'notify.msg.Msg',
    'notify.wechat.WeChat'
]

-------------------------------------------------------


在包的__init__文件中设置send_all函数

# import settings
import importlib
def send_all(countent):
    # 将settings文件中的存储函数路径迭代循环
    for path in settings.NOTIFY_LIST:
        # 通过.切割,获取每一个文件的的路径,以及cls类名
        module_path,cls_name = path.rsplit('.',maxsplit=1)
        # 通过importlib方法传入路径,获取导入文件对象
        md = importlib.import_module(module_path)
        # getattr反射获取md文件中的相对应cls类
        cls = getattr(md,cls_name)
        # 实例化类,获取一个个类的对象
        obj = cls()
        # 调用类中的发送方法
        obj.send(countent)

CSRF CSRF

1.フィッシングサイト

你自己写一个跟中国银行正规网站一模一样的页面
用户输入用户名 密码 对方账户  转账金额提交
请求确实是朝中国银行的接口发送的 钱也扣了
但是对方账户变了 变成了钓鱼网站自己提前设置好的账户

どのように達成するために

你在写form表单的时候 让用户填写的对方账户input并没有name属性
而是你自己在内部偷偷隐藏了一个具有name属性的input框
并且value值是你自己的账户 然后将该标签隐藏了

アナログは、この現象を生み出します

创建两个django项目
------------------------------------------------------
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_account" value="jason" style="display: none;">
        // 通过设置两个input框,并隐藏自定义value的框,获得该白转账人的目的
    </p>

    <p>money:<input type="text" name="money"></p>
    <input type="submit">
    
------------------------------------------------------
    
<p>这是正经的网站</p>
<form action="" method="post">
    <p>username<input type="text" name="username"></p>
    <p>target_account<input type="text" name="target_account"></p>
    <p>money:<input type="text" name="money"></p>
    <input type="submit">
</form>

この問題を解決する2

django中的中间件`'django.middleware.csrf.CsrfViewMiddleware',`就是负责校验csrf的

このサイトから送信された後の処理要求のみ

如何识别如何判断当前请求是否是本网站发出的
**防御CSRF攻击:**

    目前防御 CSRF 攻击主要有三种策略:验证 HTTP Referer 字段;在请求地址中添加 token 并验证;在 HTTP 头中自定义属性并验证。

解きます {% csrf_token %}

からフォームに追加します。 {% 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>

IMG

解決する方法3.アヤックス

モード1

  • 最初のページ上の任意の位置に書かれました{% csrf_token %}
  • そして、AJAXリクエストでのカスタムオブジェクトに付加されたタグデータが取得したランダムな文字列を送信するとき
data:{'username':'jason','csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()},

モード2

  • 最初のページ上の任意の位置に書かれました{% csrf_token %}

  • で直接データを書き込む'csrfmiddlewaretoken':'{{ csrf_token }}キーと値のペア

  • data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},    

モード3

ファイルの公式ウェブサイトで最も汎用性の高い方法を提供します

  • 新しいコードを直接のjsファイルのコピー、インポート script
  • あなたは、任意のコード関連のCSRFを記述する必要はありません
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);
    }
  }
});

静的ファイル、あなたのDjangoプロジェクトに以下の構成ファイルの前に、htmlページに自動的に私たちが問題を解決するのに役立ちます設定ファイルをインポートする(ファイルをインポートすることにより、ポストデータ検証csrf_tokenを提出AJAXは、インポートする必要がありますjQueryの、このプロファイルの内容は、達成するためにjQueryのに基づいているため)

詳細については以下を参照してくださいCSRFの内容に関するDjagno公式文書を

2つの関連するデコレータCSRF 4

二つのデコレータは、この方法は、展開図CSRFを検証する必要機能、またはパリティなしでした

1.使用

インポート

from django.views.decorators.csrf import csrf_exempt,csrf_protect

チェックしないでください @csrf_exempt

@csrf_exempt           # 不校验 csrf
def index(request):   
    return HttpResponse('index')

チェック @csrf_protect

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

CBVで2つの装飾の間2.類似点と相違点

CBV

CBV就是在url中一个路径对应一个类
    基于FBV的模式就是在Django的路由映射表里进行url和视图函数的关联,而基于CBV的模式则是在views.py文件中定义视图类,在视图类中视图函数,如get,post,put,delete等
    
    
在写代码中的几点注意事项:
    cbv定义类的时候必须要继承view
    在写url的时候必须要加as_view
    类里面使用form表单提交的话只有get和post方法
    类里面使用ajax发送数据的话支持定义以下很多方法
    restful规范:
    'get'获取数据, 'post'创建新数据, 'put'更新, 'patch'局部更新, 'delete'删除, 'head', 'options', 'trace'

----------------------------------------------------
视图函数中

from django.views import View
 
class IndexView(View):
   # 以get形式访问会执行get函数,一般情况下获取数据
   def get(self, *args, **kwargs):
      return HttpResponse('666')
 
   # 以post形式访问的话会执行post函数,一般情况下发送数据
   def post(self, *args, **kwargs):
      return HttpResponse('999')

@ csrf_exempt

このデコレータは発送のみ装備するために効果を取ることができます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_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のソース解析

另外的配置文件settings在
from django.conf import settings  中

Djangoは2つの設定ファイルを持っています

一个是暴露给用户可以配置的
            
            一个是内部全局的(用户配置了就用用户的 用户没有配就用自己的)
            obj
            obj.name = 'egon'  # 全局
            obj.name = 'jason'  # 局部
  • まずオブジェクトのグローバル構成設定をロード
  • 次いで、部分集合のロードに配置されたオブジェクトを与えます
  • かつて旧重複したエントリの上に後者
思考题
    参看django settings源码 应用到自己的项目中 
    在你的项目中 实现配置文件的插拔式设计
    用户配置了就用用户的 用户没有配就用自己的

IMG

IMG

IMG

ジャンゴ認証モジュール

1.何があります

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

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

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

スーパーユーザー(root)を作成します。

python3 manage.py createsuperuser

tool中直接createsuperuser

IMG

2.一般的な方法

2.1ユーザーの作成 create_user()

インポート表

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='[email protected]')  # 创建超级用户   需要邮箱数据

2.2チェック auth.authenticate

インポートモジュール認証

from django.contrib import auth
校验用户名和密码是否正确
user_obj = auth.authenticate(request,username=username,password=password)
# 必须传用户名和密码两个参数缺一不能

2.3ログの保存 login(request,对象)

auth.login(request,user_obj)
# 只要这句话执行了 后面在任意位置 只要你能拿到request你就可以通过request.user获取到当前登录的用户对象

2.4ログインするかどうかを判断します is_authenticated()

request.user.is_authenticated()

2.5元のパスワードが正しいことを確認 check_password(旧密码)

request.user.check_password(old_password)

2.6パスワードの変更 set_password(新密码)

获取
request.user.set_password(new_password)
request.user.save()  # 千万不要忘了

2.7ログアウト logout(request)

auth.logout(request)

# request.session.flush()

2.8ログインデコレータ @login_required

インポート

from django.contrib.auth.decorators import login_required

ローカル設定

あなたは、インターフェイス未登録のエラージャンプをカスタマイズすることができますlogin_url = '/跳转连接/'

@login_required(login_url='/login/')
def index(request):
    pass

グローバルコンフィギュレーション

settings配置文件中 直接配置
LOGIN_URL = '/login/'

然后在视图函数添加
@login_required
def index(request):
    pass

ローカル設定のグローバル設定は、ローカルの対象とした場合

3. AUTH_USERフィールドを展開

モード1

拡張外部キー1

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

モード2

オブジェクト指向の継承

导入AbstractUser类
    from django.contrib.auth.models import AbstractUser
    
定义模型表类
    class Userinfo(AbstractUser):
        phone = models.BigIntegerField()
        register_time = models.DateField(auto_now_add=True)
        
settings配置文件中设置
    AUTH_USER_MODEL = 'app01.Userinfo'  # 应用名.表名

执行数据库迁移命令

# 这么写完之后 之前所有的auth模块功能全都以你写的表为准 

スプレッド

ジャンゴ設定コンフィギュレーションファイルに基づいた設計でプラグインを達成することです

# 执行start文件中
if __name__ == '__main__':
    设置全局大字典的键值 键(随便) 值(文件的路径)
    os.environ['xxx'] = 'conf.settings'
    form lib.conf import settings
    print(settings.NAME)
    
有两个settings配置文件,分别对应暴露给用户,以及隐藏的全局配置
各自有NAME属性


------------ conf.settings.__init__配置-------------------
class Settings(object):
    def __init__(self):
        # 获取全局配置中的所有变量名
        for name in dir(global_settings):
            # 筛选出需要的大写变量名
            if name.isupper():
                # 给self对象设置全局配置中的大写变量名 属性值
                setattr(self,name,getattr(globals_settings,name))

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

# 实例化类获得对象
settings = Settings()

おすすめ

転載: www.cnblogs.com/fwzzz/p/11992591.html