赞
踩
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',
- )
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。