[Notes] Django template (2) - CSRF, verification code, URL reverse lookup

 

Notes mainly based on official documents , taking notes and extract key points, key official at containing document links. See the official documentation.

The official document: Django Documentation 

Recommended blog: Django2.2 Tutorial

The official document view layer: template layer

 

table of Contents

1.CSRF

1.1. Basic use

1.2. Decorator decorator

2. Verification Code

3.URL the reverse analysis

to sum up


 

1.CSRF

Official documentation: Cross-Site Request Forgery CSRF protection

More security-related documents: Safety

 

1.1. Basic use

CSRF spelling to Cross Site Request Forgery, translated as cross-site request forgery. CSRF attacker stole your identity to send malicious request on your behalf. CSRF can do things include: to send the name of your e-mail, messaging, steal your account, and even the purchase of goods, virtual currency transfer ...... problems caused include: disclosure of personal privacy and property safety.

When you create a Django project, enabled by default CSRF middleware. If not turned on, may be added in MIDDLEWARE provided setting.py 'django.middleware.csrf.CsrfViewMiddleware', .

CSRF is usually for the POST method . Django provides a mechanism to prevent CSRF attacks for us. The basic use is as follows :

 

For Form :

POST containing a form template, which needs to <form>add elements within a form csrf_tokentag , as shown below:

<form action="" method="post">
    {% csrf_token %}
    ....
</form>

Thus, when the form data by POST method sent to the backend server, in addition to the normal form data, but also carries a random string CSRF token, for csrf verification.

 

For Ajax :

AJAX in not as carry form as the form {% csrf_token %}token. If Django server receives a POST request is sent from the AJAX passed, the more trouble.

Solutions Django official, in front-end template JavaScript code at , add the following code, this method will be able to bring an Ajax POST CSRF tokens needed, it relies on the library Jquery, Jquery must be loaded in advance. (See the official documentation)

// using jQuery
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) {
    // 这些HTTP方法不要求CSRF包含
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

 

1.2. Decorator decorator

(1) Specify the need for separate authentication csrf

Sometimes, we close in on the whole stood CSRF function, but some need to view CSRF defense , how to do it? Django provides a csrf_protect (view) decorator.  

 csrf_protect(view) usage:

from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect

@csrf_protect
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)

Above, although the station's turned off csrf, but my_view view still be csrf verification.

NOTE: If the view class-based, reference may Decorating class-based views based decorative view class ..

(2) specified independently verified ignored csrf

Instead, open CSRF mechanism in the station's time, some view we do not want to turn CSRF mechanism . What to do about this? This requires the use Django provides us with the csrf_exempt(view) decorator of (At this point, another security issues to deal with), use:

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

@csrf_exempt
def my_view(request):
    return HttpResponse('Hello world')

(3) are provided to ensure that token csrf

Django offers a decorator, while ensuring a view to be decorated are returned along the return page in csrf token.

The decorator is: ensure_csrf_cookie (View) :

from django.views.decorators.csrf import ensure_csrf_cookie
from django.http import HttpResponse

@ensure_csrf_cookie
def my_view(request):
    return HttpResponse('Hello world')

 

In the actual development, some require authentication logon page to access and operate, then you can design a decorator login, login authentication in a decorator. And increasing the amount of code reduction logic.

 

2. Verification Code

In the user registration, login page, in order to prevent violence request , you can add a verification code function, if the code is incorrect, you do not need to continue treatment, can reduce the pressure on business servers, database servers.

Manually implement verification code (can be used online to achieve many ways)

The following code does not require manual written, because such code can be found on the Internet a lot.

1) installation package Pillow.

pip install Pillow

You can also specify the installed version. The following code uses the Image, ImageDraw, ImageFont objects and methods.

pillow:https://pillow.readthedocs.io/en/latest/index.html

Pillow related blog: https://www.cnblogs.com/linyouyi/p/11429511.html , https://blog.csdn.net/wzyaiwl/article/details/89023729

 

2) In views.py file, create a view verify_code.

  • Tip 1: randomly generated string into the session, for subsequent determination.
  • Tip 2: view returns mime-type is image / png.
from PIL import Image, ImageDraw, ImageFont
from django.utils.six import BytesIO
...
def verify_code(request):
    #引入随机函数模块
    import random
    #定义变量,用于画面的背景色、宽、高
    bgcolor = (random.randrange(20, 100), random.randrange(
        20, 100), 255)
    width = 100
    height = 25
    #创建画面对象
    im = Image.new('RGB', (width, height), bgcolor)
    #创建画笔对象
    draw = ImageDraw.Draw(im)
    #调用画笔的point()函数绘制噪点
    for i in range(0, 100):
        xy = (random.randrange(0, width), random.randrange(0, height))
        fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
        draw.point(xy, fill=fill)
    #定义验证码的备选值
    str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
    #随机选取4个值作为验证码
    rand_str = ''
    for i in range(0, 4):
        rand_str += str1[random.randrange(0, len(str1))]
    #构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont”
    font = ImageFont.truetype('FreeMono.ttf', 23)
    #构造字体颜色
    fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
    #绘制4个字
    draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)
    draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
    draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
    draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)
    #释放画笔
    del draw
    #存入session,用于做进一步验证
    request.session['verifycode'] = rand_str
    #内存文件操作
    buf = BytesIO()
    #将图片保存在内存中,文件类型为png
    im.save(buf, 'png')
    #将内存中的图片数据返回给客户端,MIME类型为图片png
    return HttpResponse(buf.getvalue(), 'image/png')

3) Open the  application /urls.py files, configuration url.

    path('verify_code', views.verify_code, name='verify_code'),  # 产生验证码图片

4) Run the server, enter the following URL in your browser. You can see the code generated.

http://127.0.0.1:8000/verify_code

When the need to verify, in the view key code is as follows :

    # 获取用户输入验证码
    vcode1 = request.POST.get('vcode')
    # 获取session中保存的验证码
    vcode2 = request.session.get('verifycode')
    # 进行验证码校验
    if vcode1 != vcode2:
        # 验证码错误
        return redirect('/login')  # 检验失败,重定向到一个页面

 

 

3. reverse analysis of the URL

Official documents: URL scheduler ( processing request , the path converter , using regular expressions , the URLconf section which matches the URL , include other URLconfs (forward route) , the reverse of parsing the URL  , etc.)

Blog: https://www.liujiangblog.com/course/django/136

to sum up

 

In the actual Django project, it is often required to obtain a bar URL, URL link to the configuration generated content.

It is best not hard-coded URL (consuming, can not be extended, error-prone). URL design as generated and do not use URL and temporary mechanism URLconf described, this URL will lead over time to become obsolete.

We need a secure, reliable and adaptive mechanisms, when modify the code in the URLconf, without having to search a wide range of projects in the source code, replace the failed hard-coded URL. Django provides a solution, just a name parameter in the URL , and you assign a custom, easy to remember and intuitive string.

 

Where needed to resolve a URL, for different levels, Django offers different tools for reverse lookup URL:

  • In the template there: use  url template tags. (That is, write the front page)
  • In Python coding : the use of  reverse() functions. (That is, when the case of a write view functions, etc.)
  • In the Advanced URL handling code associated with the model instance of Django, use the:  get_absolute_url() method. (That is, the model model)

 

(1) name Parameter

By name parameter , you can reverse lookup URL , reverse URL matching , reverse URL query or simple URL reverse lookup .

Examples are as follows:

Note name URLconf :( parameters: name = 'news-year-archive')

from django.urls import path

from . import views

# 如果是app的urls,这里加上:app_name = '应用名'
urlpatterns = [
    #...
    path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
    #...
]

Based on the above, and in 2020  the corresponding URL is a  /articles/2020/ .

 

In the following ways you can use the template code to get them:

硬编码的链接(只能访问/articles/2012):<br/>
<a href="/articles/2012/">2012 Archive</a><br/>

解析动态生成链接(能访问 "articles/<int:year>/" 格式的路径):<br/>
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
{# Or with the year in a template context variable: #}

<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

 

Or in the Python code inside: from django.urls import reverse, then use the  reverse() function

from django.http import HttpResponseRedirect
from django.urls import reverse

def redirect_to_year(request):
    # ...
    year = 2020
    # ...
    return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

Play a central role through  name='news-year-archive' to the name from a url that can be referenced .

Two different app, if taken in their urlconf the same name for a one url, it will cause trouble. You can use the namespace to solve the problem.

 

(2)URL namespaces

URL namespace can be guaranteed even if the same app use different URL name, can be found only anti URL. Each URL is recommended to use a custom application with a namespace.

Django example to the document, for example, to achieve namespace approach is very simple, add urlconf file app_name = 'polls'and namespace='author-polls'that similar definitions .

The recommended app_name = 'polls'way. Examples refer to the official document, click on the title visible.

 

(3) the URL of space and include the name URLconf

You can specify the URLconf include two ways the Application Namespaces .

The first (recommended) :

URLconf to include in module, set app_nameattributes , which is the same level urlpatterns properties . Must be the actual module or string of modules passed by reference to  include(), i.e., as  include()的参数, instead of a list urlpatterns itself.

polls/urls.py:app_name = 'polls'

from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    ...
]

urls.py

from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
]

At this time, polls.urls the URL having a defined application name space polls (corresponding to app_name = 'polls').

The second , see the official documentation.

 

to sum up

In short, according to the configuration reverse analysis can dynamically generating path url, which is the main purpose.

Use reverse lookup :

  1. In applications urls.py front urlpatterns, the write  app_name = 'application name' ;
  2. To each application in view url write parameter name , such as: path ( 'index', views.index, name = 'index' ), ; (this step should operate as diet)
  3. In the project urls.py when urls.py include an application in the include function to write the parameters namespace = 'specifies the name' ; (Django2.x in fact, can not write namespace reverse lookup)

In the template : may be used  {% url 'application name (i.e. APP_NAME) : View name (i.e., name) '%}  format reverse resolution, to generate linking,

如:<a href="{% url 'booktest:index' %}">首页</a>

In view: Import from django.urls Import Reverse ,

使用reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)[源代码]

(viewname Url name pattern may be a view or a callable objects, such as "application name: View name ' .

 You can be dynamically generated links, as follows:

from django.urls import reverse
...
# /test_redirect
def test_redirect(request):
    # 重定向到/index
    # return redirect('/index')  # 硬编码写死
    
    # 动态生成链接
    url = reverse('booktest:index')
    return redirect(url)

 

 

 

 

-----end-----

Published 50 original articles · won praise 10 · views 6591

Guess you like

Origin blog.csdn.net/qq_23996069/article/details/104889157