【ジャンゴ】認証システム--2019-08-09 11時22分49秒

オリジナル:http://106.13.73.98/__/44/

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

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

追加:Djangoのビルトインの現在の時刻を生成する方法

from django.utils.timezone import now
now_time = now()  # 生成当前时间
# 时间格式示例:2018-11-22 05:17:09.538525+00:00
# 它生成的时间格式能够与数据库中的auto_now/auto_now_add生成的时间做计算.


#。認証モジュール

# 导入auth模块
from django.contrib import auth

1.認定認証()

つまり、ユーザー名とパスワードが正しいことを確認するために、ユーザ認証機能を提供し、それは通常、ユーザー名、パスワード二つの重要なパラメータを取ります。

認証は(有効なユーザー名とパスワードが正しい)に成功した場合、それはユーザーオブジェクトを返します。

()認証ユーザがユーザを認証した識別するために、オブジェクトの後端にプロパティを設定し、それ以降の処理において、ログイン情報が必要です。

使用法:

# user = auth.authenticate(request, **form_obj.cleaned_data)
user = auth.authenticate(request, username="用户名", password="密码")

2.ログインログイン(HttpRequestの、ユーザー)

この関数は、HttpRequestを対象と認定され、ユーザーオブジェクトを受け取ります。

この機能は、ユーザーのログイン機能を実装しています。本質的には、後端部にユーザーのセッション関連のデータを生成します。

セッションデータテーブルと呼ばれる:django_session、ブラウザに対応するレコードを。

例:
ここに画像を挿入説明
***

3.償却ログアウト(リクエスト)

この関数は、HttpRequestのオブジェクト、ノーリターン値をとります。

関数が呼び出されると、現在の要求は、すべてのセッション情報をクリアします。ユーザーがログインしていない場合であっても、また文句はありません。この機能を使用しています。

例:
ここに画像を挿入説明
***

4.認証)(is_authenticated判定します

認証により、現在のリクエスト(ログインユーザがある)かどうかを判断するために使用します。

例:
ここに画像を挿入説明
***

着陸チェックlogin_requierd()

認証は、ビューにチェックを追加する簡単なログインのための装飾的なツールを提供してくれます。

ユーザーがログインしていない場合、それはDjangoのデフォルトのログインURLにジャンプします「/アカウント/ログイン/」、絶対パスにアクセスするには、現在のURLを渡して(成功した着陸後、パスにリダイレクトされます)。

カスタム・ログインURLが必要な場合は==、あなたは以下のように変更LOGIN_URLによってsettings.pyファイルにする必要があります==

# 修改默认的登陆URL为'/login/':
LOGIN_URL = '/login/'

使用法:

# 用于验证是否登陆的装饰器
from django.contrib.auth.decorators import login_required  

@login_required
def home(request):
    pass

6.(通常のユーザーCREATE_USERを作成します)

新しいユーザ認証オファーを作成する方法、そうで必要なパラメータ(ユーザ名、パスワード)とを提供することが必要です。

例:
ここに画像を挿入説明
***

7.(スーパーユーザーcreate_superuserを作成します)

新しいスーパーユーザーの認証を作成すると、必要なパラメータ(電子メール、ユーザ名、パスワード)を提供する方法を提供します。

例:
ここに画像を挿入説明
***

8.暗号チェックサムのcheck_password(パスワード)

パスワード認証のオファーかどうかを確認する正しい方法は、現在のリクエストのユーザーのパスワードを提供する必要があります。

パスワードが正しいリターン真、そうでなければFalseです。

例:
ここに画像を挿入説明
***

9. [パスワードの変更] set_password(new_passwordを)

AUTHによって提供されたパスワードを変更する方法は、パラメータとして設定される新しいパスワードを受け取りました。

==注意:ユーザーオブジェクトの保存メソッドを呼び出してください設定した後!==

例:
ここに画像を挿入説明

プロパティユーザーオブジェクト

重要な属性:

  • ユーザー名:ユーザー名
  • パスワード:パスワードの暗号文
  • is_staff:ユーザーがサイト(か着陸管理バックエンド)への管理者権限を持っているかどうか。
  • is_active:是否允许用户登陆,设置为False后,可以在不删除用户的前提下禁止用户登陆.
    对禁用的用户调用auth.authenticate()方法将返回None

==request.user.xx :返回xx字段的值(xx可以为auth_user表中的所有字段名).
request.user :默认返回username字段的值.==

扩展默认的auth_user表

这内置的认证系统这么好用,但是auth_user表字段都是固定的那几个,我在项目中没法拿来直接使用啊!

比如,我想要加一个存储用户手机号的字段,怎么办?

聪明的你可能会想到新建另外一张表然后通过一对一和内置的auth_user表关联,这样虽然能满足要求但是有没有更好的实现方式呢?

答案是当然有了。

我们可以通过继承内置的 AbstractUser 类,来定义一个自己的Model类。

这样既能根据项目需求灵活的设计用户表,又能使用Django强大的认证系统了。

from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
    """
    用户信息表
    """
    nid = models.AutoField(primary_key=True)
    phone = models.CharField(max_length=11, null=True, unique=True)
    
    def __str__(self):
        return self.username

注意:
按上面的方式扩展了内置的auth_user表之后,一定要在settings.py中告诉Django,我现在使用我新定义的UserInfo表来做用户认证。写法如下:

# 引用Django自带的User表,继承使用时需要设置
AUTH_USER_MODEL = 'app名.UserInfo'

再次注意:
==一旦我们指定了新的认证系统所使用的表,我们就需要重新在数据库中创建该表,而不能继续使用原来默认的auth_user表了。==

auth实现

实现功能:注册用户、登陆、注销、修改密码、登陆校验

==settings.py文件增加配置项:==

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

==urls.py文件:==

from django.conf.urls import url
from django.contrib import admin
from blog import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^register/$', views.register),
    url(r'^login/$', views.login),
    url(r'^index01/$', views.index01),
    url(r'^index02/$', views.index02),
    url(r'^logout/$', views.logout),
    url(r'^change_password/$', views.change_password),
    url(r'^ajax_register/$', views.ajax_register),
]

==forms.py文件:==

from django import forms
from django.forms import Form
from django.forms import widgets
from django.core.exceptions import ValidationError  # 用于抛出错误信息


# 用户登陆验证
class LoginForm(Form):
    username = forms.CharField(
        label="用户名",
        min_length=2,
        max_length=6,
        error_messages={
            'required': "用户名不能为空",
            'invalid': "用户名格式错误",
            'min_length': "用户名最短2位",
        },  # 自定义错误提示
    )

    password = forms.CharField(
        label="密码",
        min_length=6,
        max_length=12,
        error_messages={
            'required': "密码不能为空",
            'invalid': "密码格式错误",
            'min_length': "密码最短6位",
        },
        widget=widgets.PasswordInput(),  # 指定input框的type类型password
    )


# 注册验证
class RegForm(Form):
    username = forms.CharField(
        label="用户名",
        min_length=2,
        max_length=6,
        error_messages={
            'required': "用户名不能为空",
            'invalid': "用户名格式错误",
            'min_length': "用户名最短2位",
        },  # 自定义错误提示
    )

    password = forms.CharField(
        label="密码",
        min_length=6,
        max_length=12,
        error_messages={
            'required': "密码不能为空",
            'invalid': "密码格式错误",
            'min_length': "密码最短6位",
        },
        widget=widgets.PasswordInput(),
    )

    re_password = forms.CharField(
        label="确认密码",
        min_length=6,
        max_length=12,
        error_messages={
            'required': "验证密码不能为空",
            'invalid': "密码格式错误",
            'min_length': "密码最短6位",
        },
        widget=widgets.PasswordInput(),
    )

    def clean_re_password(self, *args, **kwargs):
        password = self.cleaned_data.get('password')
        re_password = self.cleaned_data.get('re_password')
        if password == re_password:
            return password
        raise ValidationError("密码不一致")

    # 单选按钮
    level = forms.fields.ChoiceField(
        label="用户级别",
        choices=((0, "普通用户"), (1, "超级用户"),),
        initial=0,  # 默认选择普通用户
        widget=forms.widgets.RadioSelect(),
    )


# 修改密码
class ChangePwd(Form):
    old_password = forms.CharField(
        label="旧密码",
        min_length=6,
        max_length=12,
        error_messages={
            'required': "旧密码不能为空",
            'invalid': "密码格式错误",
            'min_length': "密码最短6位",
        },
        widget=widgets.PasswordInput(),
    )

    password = forms.CharField(
        label="新密码",
        min_length=6,
        max_length=12,
        error_messages={
            'required': "新密码不能为空",
            'invalid': "密码格式错误",
            'min_length': "密码最短6位",
        },
        widget=widgets.PasswordInput(),
    )

    re_password = forms.CharField(
        label="确认新密码",
        min_length=6,
        max_length=12,
        error_messages={
            'required': "验证密码不能为空",
            'invalid': "密码格式错误",
            'min_length': "密码最短6位",
        },
        widget=widgets.PasswordInput(),
    )

    def clean_re_password(self, *args, **kwargs):
        password = self.cleaned_data.get('password')
        re_password = self.cleaned_data.get('re_password')
        if password == re_password:
            return password
        raise ValidationError("密码不一致")

==views.py文件:==

from django.shortcuts import render, redirect, HttpResponse
from blog.forms import *  # 导入自定义的Form组件
from django.contrib import auth  # 导入认证模块
from django.contrib.auth.models import User  # 导入User表
from django.contrib.auth.decorators import login_required  # 用于验证是否登陆的装饰器
from blog072 import settings


# 注册
def register(request):
    form_obj = RegForm()
    if request.method == 'POST':
        form_obj = RegForm(request.POST)
        if form_obj.is_valid():
            form_obj.cleaned_data.pop('re_password')
            level = form_obj.cleaned_data.pop('level')
            # 判断要注册的用户类型
            if not int(level):
                # 使用create()方法创建的用户为明文密码,无法登陆(不可使用此方法)
                # User.objects.create(**form_obj.cleaned_data)
                # create_user():创建普通用户
                User.objects.create_user(is_staff=1, **form_obj.cleaned_data)
                # is_staff=1:允许登陆后台(默认不允许)
            else:
                # create_superuser():创建超级用户
                User.objects.create_superuser(email='', **form_obj.cleaned_data)
            return redirect('/login/')
    return render(request, 'register.html', {'form': form_obj})


# 登陆
def login(request):
    form_obj = LoginForm()
    if request.method == 'POST':
        form_obj = LoginForm(request.POST)
        if form_obj.is_valid():
            # 只有执行了is_valid之后,才可执行cleaned_data方法,且cleaned_data内的数据是经过校验的
            user = auth.authenticate(request, **form_obj.cleaned_data)
            # 如果校验成功,user是当前登陆用户对象,否则为None(用户被禁用[is_active=0]后,也会返回None)
            if user:
                # 生成session数据(表名:django_session  一个浏览器对应一条session数据)
                auth.login(request, user)
                # 如果是跳转过来的,则登陆成功后返回至原页面:
                next = request.GET.get('next')
                ret = next if next else '/index01/'
                return redirect(ret)
            print(form_obj.cleaned_data)
            return HttpResponse("用户名或密码错误")
    return render(request, 'login.html', {'form': form_obj})


@login_required
def index01(request):
    print("用户%s进入index01页面" % request.user)
    # request.user.xx  :xx可以为auth_user表中的所有字段名
    # request.user 默认返回username字段
    return render(request, 'index01.html')


def index02(request):
    if not request.user.is_authenticated():
        # is_authenticated():判断当前请求是否通过了认证
        ret = '%s?next=%s' % (settings.LOGIN_URL, request.path)
        return redirect(ret)
    print("用户%s进入index02页面" % request.user)
    return render(request, 'index02.html')


# 注销
@login_required
def logout(request):
    # 注销,清除session数据
    auth.logout(request)
    return redirect('/login/')


# 修改密码
@login_required
def change_password(request):
    form_obj = ChangePwd()
    if request.method == 'POST':
        form_obj = ChangePwd(request.POST)
        if form_obj.is_valid():
            old_password = form_obj.cleaned_data.get('old_password')
            password = form_obj.cleaned_data.get('password')
            # 判断旧密码是否正确
            if request.user.check_password(old_password):
                # 修改密码
                request.user.set_password(password)
                request.user.save()  # 同步到数据库
                return redirect('/login/')
            return HttpResponse("旧密码错误!")
    return render(request, 'change_password.html', {'form': form_obj})


# ajax判断用户名是否存在
def ajax_register(request):
    username = request.GET.get('username')
    print(username)
    print(User.objects.filter(username=username).exists())
    if User.objects.filter(username=username).exists():
        return HttpResponse("0")
    return HttpResponse()

==HTML文件:==
==注册页面(register.html):==

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta http-equiv="content-Type" charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
    <title>我是注册页面</title>
</head>
<body>
<form action="" method="post" novalidate>
    {% csrf_token %}
    <p id="sign01">
        {{ form.username.label }}
        {{ form.username }}
        <span style="color: red">{{ form.username.errors.0 }}</span>
        <span id="sign02" style="color: red"></span>
    </p>
    <p>
        {{ form.password.label }}
        {{ form.password }}
        <span style="color: red">{{ form.password.errors.0 }}</span>
    </p>
    <p>
        {{ form.re_password.label }}
        {{ form.re_password }}
        <span style="color: red">{{ form.re_password.errors.0 }}</span>
    </p>
    <p>
        {{ form.level.label }}
        {{ form.level }}
    </p>
    <p>
        <button>注册</button>
        <span style="font-size: 50%;">注册成功将返回登陆页面</span>
    </p>
</form>
{% load static %}


</body>
</html>

==登陆页面(login.html):==

{# bootstrap版登陆页面 #}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta http-equiv="content-Type" charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    {# 需要下载bootstrap样式文件 #}
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
    <title>我是登陆页面</title>
</head>
<body>
<form class="form-horizontal" action="" method="post" novalidate>
    {% csrf_token %}
    <div class="form-group">
        <label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">用户名</label>
        <div class="col-sm-10">
            {{ form.username }}
            {# has-error:Form组件要想展示红色错误信息,必须要加这个类 #}
            <div class="has-error">
                <span class="help-block">{{ form.username.errors.0 }}</span>
            </div>
        </div>
    </div>
    <div class="form-group">
        <label for="{{ form.password.id_for_label }}" class="col-sm-2 control-label">密码</label>
        <div class="col-sm-10 has-error">
            {{ form.password }}
            <div class="has-error">
                <span class="help-block">{{ form.password.errors.0 }}</span>
            </div>
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-default">登陆</button>
            <a href="/register/" class="btn btn-sm">注册用户</a>
        </div>
    </div>
</form>
</body>
</html>

==index01.py页面:==

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta http-equiv="content-Type" charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
    <title>index01</title>
</head>
<body>
<h1>我是 Index01 页面</h1>
<a href="/logout/">注销</a>
<a href="/change_password/">修改密码</a>
</body>
</html>

== index02.pyページ:==

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta http-equiv="content-Type" charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
    <title>index02</title>
</head>
<body>
<h1>我是 Index02 页面</h1>
<a href="/logout/">注销</a>
<a href="/change_password/">修改密码</a>
</body>
</html>

==パスワード変更ページ(change_password.html):==

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta http-equiv="content-Type" charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
    <title>我是修改密码页面</title>
</head>
<body>
<form action="" method="post" novalidate>
    {% csrf_token %}
    <p>
        {{ form.old_password.label }}
        {{ form.old_password }}
        <span style="color: red">{{ form.odl_password.errors.0 }}</span>
    </p>
    <p>
        {{ form.password.label }}
        {{ form.password }}
        <span style="color: red">{{ form.password.errors.0 }}</span>
    </p>
    <p>
        {{ form.re_password.label }}
        {{ form.re_password }}
        <span style="color: red">{{ form.re_password.errors.0 }}</span>
    </p>
    <p>
        <button>提交</button>
        <span style="font-size: 50%;">修改成功后将返回登陆页面</span>
    </p>
</form>
</body>
</html>

オリジナル:http://106.13.73.98/__/44/

おすすめ

転載: www.cnblogs.com/gqy02/p/11326085.html