Django用户认证

    django的用户认证有很多方法,可以自己写,也有很多第三方的模块。本文记录的是使用Django自带的认证模块的方法,不需要任何其他第三方的包。

    1、基本配置

    新建好project后,检查settings.py,确保INSTALLED_APPS和MIDDLEWARE中,包含以下模块

INSTALLED_APPS = [
    # 其它应用列表...
    'django.contrib.auth',
    'django.contrib.contenttypes',
]
MIDDLEWARE = [
    # 其它中间列表...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
]

     2、添加必要文件

    新建一个app,取名为users,并在settings.py的INSTALLED_APPS中加入'users'

    新建文件夹templates,在settings.py中修改指定templates的路径:

TEMPLATES = [
    {
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        #其他配置
    },
]

    在users目录和templates目录中加入相关的模型和模板文件,最后整个工程的结构如下:

    下面介绍各个文件的作用和具体内容:

    (1)users/models.py

    自定义的用户模型,继承AbstractUser,获得username、password、email、first_name、last_name等属性,可以自己添加相关的属性。

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models
from django.contrib.auth.models import AbstractUser

# Create your models here.

class User(AbstractUser):
	nick_name = models.CharField(max_length=50, blank=True)

	class Meta(AbstractUser.Meta):
		pass

    此外,还需在settings.py中设置认证的用户模型,并对语言和时区进行修改。

LANGUAGE_CODE = 'zh-hans' #修改
TIME_ZONE = 'Asia/Shanghai' #修改
AUTH_USER_MODEL = 'users.User' #添加

     修改好之后,执行python manage.py makemigrations 和 python manage.py migrate命令,更新数据库

    (2)注册部分:users/forms.py和register.html

     Django 用户系统内置了登录、修改密码、找回密码等视图,但是唯独用户注册的视图函数没有提供,这一部分需要我们自己来写。

     首先,新建注册需要显示的表单模型:users/forms.py

     继承自UserCreationForm,但需对用户模型、显示的field内容进行修改。(密码和密码确认不用修改,会自动显示)

#coding: utf-8
from django.contrib.auth.forms import UserCreationForm
from .models import User

class RegisterForm(UserCreationForm):
	class Meta(UserCreationForm.Meta):
		model = User #表单对应的模型
		fields =("username", "email") #需要渲染的控件。默认有用户名、密码、密码确认,此处增加email

    其次,新建注册页面的html模板templates/registration/register.html

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="x-ua-compatible" content="ie=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
	<link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">

	<title>注册</title>
	<style>
		.errorlist{
			color: red;
		}
	</style>
</head>
<body>
	<div class="flex-center">
		<div class="container">
			<div class="flex-center">
				<div class="unit-1-2 unit-1-on-mobile">
					<h3 class="flex-center">注册</h3>
					<form class="form" action="{% url 'users:register' %}" method="post">
						{% csrf_token %}
						{% for field in form %}
							{{ field.label_tag }}
							{{ field }}
							{{ field.errors }}
							{% if field.help_text %}
								<p class="help text-small text-muted">{{ field.help_text|safe }}</p>
							{% endif %}
						{% endfor %}
						<button type="submit" class="btn btn-primary btn-block">注册</button>
					</form>
				</div>
			</div>
		</div>
	</div>
</body>
</html>

    在users/views.py中,新建注册对应的视图函数,并把上面的RegisterForm模型传给html模板

def register(request):
	if request.method == 'POST':
		form = RegisterForm(request.POST)

		if form.is_valid():
			form.save()
			return redirect('/')

	else:
		form = RegisterForm()
	return render(request, 'registration/register.html', context={'form': form})

    最后,在urls.py中添加注册的url:

    learn_auth/urls.py:

from django.conf.urls import url, include
from django.contrib import admin
from users import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^users/', include('users.urls')),
    url(r'^users/', include('django.contrib.auth.urls')),
    url(r'^$', views.index, name='index'),
]

    users/urls.py:

from django.conf.urls import url
from . import views

app_name = 'users'

urlpatterns = [
	url(r'^register/', views.register, name='register')
]

   至此,启动服务器,访问localhost:8000/users/register即可进行注册了,并会自动带有错误提示功能。效果如下图(注册完成后,跳转至"/",但该功能未实现,会报错,但实际上已经注册成功,可以打开admin页面查看用户信息是否已经加入数据库)

 

    (3)登录部分:login.html

    Django 自带有登录的视图函数,url模式在django.contrib.auth.urls中,在工程的urls.py中添加该url即可访问到

url(r'^users/', include('django.contrib.auth.urls'))

    自带的视图函数会自动检查数据库,给出登录结果,我们要做的就是提供一个模板文件,用以输入信息和显示登录结果。

    登录模块默认调用templates/registration/login.html模块,因此,需要在registration目录下新建login.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>登录</title>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
    <style>
        .errorlist {
            color: red;
        }
    </style>
</head>
<body>
<div class="flex-center">
    <div class="container">
        <div class="flex-center">
            <div class="unit-1-2 unit-1-on-mobile">
                <h3>登录</h3>
                <form class="form" action="{% url 'login' %}" method="post">
                    {% csrf_token %}
                    {{ form.non_field_errors }}
                    {% for field in form %}
                        {{ field.label_tag }}
                        {{ field }}
                        {{ field.errors }}
                        {% if field.help_text %}
                            <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
                        {% endif %}
                    {% endfor %}
                    <button type="submit" class="btn btn-primary btn-block">登录</button>
                    <input type="hidden" name="next" value="{{ next }}"/>
                </form>
                <div class="flex-left top-gap text-small">
                    <div class="unit-2-3"><span>没有账号?<a href="{% url 'users:register' %}">立即注册</a></span></div>
                    <div class="unit-1-3 flex-right"><span><a href="{% url 'password_reset' %}">忘记密码?</a></span></div>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

    新建index.html,在其中判断用户是否已登录,若未登录则给出登录连接

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>首页</title>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
</head>
<body>
<div class="flex-center">
    <div class="container">
        <div>
            <h1 class="logo"><a href="{% url 'index' %}">Django Auth Example</a></h1>
            {% if user.is_authenticated %}
                <p>你已登录,欢迎你:<a href="#">{{ user.username }}</a></p>
                <button class="btn btn-default"><a href="{% url 'logout' %}?next={{ request.path }}">注销登录</a></button>
                <button class="btn btn-default"><a href="{% url 'password_change' %}?next={{ request.path }}">修改密码</a></button>
            {% else %}
                <p>你还没有登录,请
                    <button class="btn btn-default"><a href="{% url 'login' %}?next={{ request.path }}">登录</a></button>
                    或者
                    <button class="btn btn-default"><a href="{% url 'users:register' %}?next={{ request.path }}">注册</a></button>
                </p>
            {% endif %}
        </div>
    </div>
</div>
</body>
</html>

    (4)注销部分:注销不需要模板,直接调用{% url 'users:register' %}即可。

    (5)修改密码部分:password_change_form.html和password_change_done.html

    当用户需要修改密码时,调用的自带视图函数地址为{% url 'password_change' %}?next={{ request.path }}

    需要做的,是添加修改页面和修改成功页面两个html模板password_change_form.html和password_change_done.html。

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>修改密码</title>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
    <style>
        .errorlist {
            color: red;
        }
    </style>
</head>
<body>
<div class="flex-center">
    <div class="container">
        <div class="flex-center">
            <div class="unit-1-2 unit-1-on-mobile">
                <h1><a href="{% url 'index' %}">Django Auth Example</a></h1>
                <h3>修改密码</h3>
                <form class="form" action="{% url 'password_change' %}" method="post">
                    {% csrf_token %}
                    {{ form.non_field_errors }}
                    {% for field in form %}
                        {{ field.label_tag }}
                        {{ field }}
                        {{ field.errors }}
                        {% if field.help_text %}
                            <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
                        {% endif %}
                    {% endfor %}
                    <button type="submit" class="btn btn-primary btn-block">确认修改</button>
                </form>
            </div>
        </div>
    </div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>密码修改成功</title>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
</head>
<body>
<div class="flex-center">
    <div class="container">
        <div>
            <h1 class="logo"><a href="{% url 'index' %}">Django Auth Example</a></h1>
            <p>密码修改成功!</p>
        </div>
    </div>
</div>
</body>
</html>

     (6)重置密码:password_reset_form.html、password_reset_confirm.html、  password_reset_done.html、 password_reset_complete.html

    一般重置密码流程为:用户点击“忘记密码”,页面跳转到reset_form.html,输入邮箱和相关信息,点击提交,页面跳转到reset_done页面。后台发送重置邮件给用户,并提供重置密码的页面地址,用户打开reset_confirm页面,设置新的密码并提交,页面跳转到reset_complete页面。

    django自带发邮件的功能,只需要在settings.py中进行相关配置,如下面的配置是把邮件发送给终端

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

    调用自带重置密码的url:{% url 'password_reset' %}

    reset_form和reset_conform的主要部分的内容如下(reset_done和reset_complete只是简单的静态提示内容)

    password_reset_form.html :

<form class="form" action="{% url 'password_reset' %}" method="post">
                    {% csrf_token %}
                    {{ form.non_field_errors }}
                    {% for field in form %}
                        {{ field.label_tag }}
                        {{ field }}
                        {{ field.errors }}
                        {% if field.help_text %}
                            <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
                        {% endif %}
                    {% endfor %}
                    <button type="submit" class="btn btn-primary btn-block">提交</button>
</form>

    password_reset_confirm.html

<form class="form" method="post">
                    {% csrf_token %}
                    {{ form.non_field_errors }}
                    {% for field in form %}
                        {{ field.label_tag }}
                        {{ field }}
                        {{ field.errors }}
                        {% if field.help_text %}
                            <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
                        {% endif %}
                    {% endfor %}
                    <button type="submit" class="btn btn-primary btn-block">提交</button>
</form>

    

 (7)关于注册、登录、注销后的跳转问题

    注册、登录、注销等操作后,一般希望页面跳回到原先访问的地方,而不是跳到其他页面。解决方法是在url中添加一个next参数:

<p>你还没有登录,请
    <button class="btn btn-default"><a href="{% url 'login' %}?next={{ request.path }}">登录</a></button>
    或者
    <button class="btn btn-default"><a href="{% url 'users:register' %}?next={{ request.path }}">注册</a></button>
</p>

    其中,在login时,因为调用视图函数后,会先访问login.html,并把next参数带过去,而后提交表单给视图函数,此时是一次新的调用,需要把next参数再带回去。方法是在表单后面添加一个hidden的输入

               <form class="form" action="{% url 'login' %}" method="post">
                    {% csrf_token %}
                    {{ form.non_field_errors }}
                    {% for field in form %}
                        {{ field.label_tag }}
                        {{ field }}
                        {{ field.errors }}
                        {% if field.help_text %}
                            <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
                        {% endif %}
                    {% endfor %}
                    <button type="submit" class="btn btn-primary btn-block">登录</button>
                    <input type="hidden" name="next" value="{{ next }}"/>
                </form>

     其次,对于用户直接在地址栏输入登录等页面地址的情况,在settings.py中设置默认跳转到首页

LOGOUT_REDIRECT_URL = '/' #没有next参数时的默认注销后跳转地址
LOGIN_REDIRECT_URL = '/' #没有next参数时的默认登录后跳转地址

    3、扩展

    自带的模块只能通过用户名和密码来认证,如果想要登录时可以通过邮件等其他方式来认证,需要自定义认证模块。

    在users目录下新建backends.py,实现authenticate和get_user方法

from .models import User

class EmailBackend(object):
    def authenticate(self, request, **credentials):
        # 要注意登录表单中用户输入的用户名或者邮箱的 field 名均为 username
        email = credentials.get('email', credentials.get('username'))
        try:
            user = User.objects.get(email=email)
        except User.DoesNotExist:
            pass
        else:
            if user.check_password(credentials["password"]):
                return user

    def get_user(self, user_id):
        """
        该方法是必须的
        """
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

       配置settings.py:

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'users.backends.EmailBackend',
)

 

    参考文献:https://www.zmrenwu.com/post/50/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值