当前位置:   article > 正文

Django用户认证_django.contrib.auth.urls

django.contrib.auth.urls

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

    1、基本配置

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

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

     2、添加必要文件

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

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

  1. TEMPLATES = [
  2. {
  3. 'DIRS': [os.path.join(BASE_DIR, 'templates')],
  4. #其他配置
  5. },
  6. ]

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

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

    (1)users/models.py

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

  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. from django.db import models
  4. from django.contrib.auth.models import AbstractUser
  5. # Create your models here.
  6. class User(AbstractUser):
  7. nick_name = models.CharField(max_length=50, blank=True)
  8. class Meta(AbstractUser.Meta):
  9. pass

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

  1. LANGUAGE_CODE = 'zh-hans' #修改
  2. TIME_ZONE = 'Asia/Shanghai' #修改
  3. 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内容进行修改。(密码和密码确认不用修改,会自动显示)

  1. #coding: utf-8
  2. from django.contrib.auth.forms import UserCreationForm
  3. from .models import User
  4. class RegisterForm(UserCreationForm):
  5. class Meta(UserCreationForm.Meta):
  6. model = User #表单对应的模型
  7. fields =("username", "email") #需要渲染的控件。默认有用户名、密码、密码确认,此处增加email

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

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="x-ua-compatible" content="ie=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  7. <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
  8. <title>注册</title>
  9. <style>
  10. .errorlist{
  11. color: red;
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <div class="flex-center">
  17. <div class="container">
  18. <div class="flex-center">
  19. <div class="unit-1-2 unit-1-on-mobile">
  20. <h3 class="flex-center">注册</h3>
  21. <form class="form" action="{% url 'users:register' %}" method="post">
  22. {% csrf_token %}
  23. {% for field in form %}
  24. {{ field.label_tag }}
  25. {{ field }}
  26. {{ field.errors }}
  27. {% if field.help_text %}
  28. <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
  29. {% endif %}
  30. {% endfor %}
  31. <button type="submit" class="btn btn-primary btn-block">注册</button>
  32. </form>
  33. </div>
  34. </div>
  35. </div>
  36. </div>
  37. </body>
  38. </html>

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

  1. def register(request):
  2. if request.method == 'POST':
  3. form = RegisterForm(request.POST)
  4. if form.is_valid():
  5. form.save()
  6. return redirect('/')
  7. else:
  8. form = RegisterForm()
  9. return render(request, 'registration/register.html', context={'form': form})

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

    learn_auth/urls.py:

  1. from django.conf.urls import url, include
  2. from django.contrib import admin
  3. from users import views
  4. urlpatterns = [
  5. url(r'^admin/', admin.site.urls),
  6. url(r'^users/', include('users.urls')),
  7. url(r'^users/', include('django.contrib.auth.urls')),
  8. url(r'^$', views.index, name='index'),
  9. ]

    users/urls.py:

  1. from django.conf.urls import url
  2. from . import views
  3. app_name = 'users'
  4. urlpatterns = [
  5. url(r'^register/', views.register, name='register')
  6. ]

   至此,启动服务器,访问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

  1. <!DOCTYPE html>
  2. <html lang="zh-cn">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="x-ua-compatible" content="ie=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  7. <title>登录</title>
  8. <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
  9. <style>
  10. .errorlist {
  11. color: red;
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <div class="flex-center">
  17. <div class="container">
  18. <div class="flex-center">
  19. <div class="unit-1-2 unit-1-on-mobile">
  20. <h3>登录</h3>
  21. <form class="form" action="{% url 'login' %}" method="post">
  22. {% csrf_token %}
  23. {{ form.non_field_errors }}
  24. {% for field in form %}
  25. {{ field.label_tag }}
  26. {{ field }}
  27. {{ field.errors }}
  28. {% if field.help_text %}
  29. <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
  30. {% endif %}
  31. {% endfor %}
  32. <button type="submit" class="btn btn-primary btn-block">登录</button>
  33. <input type="hidden" name="next" value="{{ next }}"/>
  34. </form>
  35. <div class="flex-left top-gap text-small">
  36. <div class="unit-2-3"><span>没有账号?<a href="{% url 'users:register' %}">立即注册</a></span></div>
  37. <div class="unit-1-3 flex-right"><span><a href="{% url 'password_reset' %}">忘记密码?</a></span></div>
  38. </div>
  39. </div>
  40. </div>
  41. </div>
  42. </div>
  43. </body>
  44. </html>

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

  1. <!DOCTYPE html>
  2. <html lang="zh-cn">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="x-ua-compatible" content="ie=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  7. <title>首页</title>
  8. <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
  9. </head>
  10. <body>
  11. <div class="flex-center">
  12. <div class="container">
  13. <div>
  14. <h1 class="logo"><a href="{% url 'index' %}">Django Auth Example</a></h1>
  15. {% if user.is_authenticated %}
  16. <p>你已登录,欢迎你:<a href="#">{{ user.username }}</a></p>
  17. <button class="btn btn-default"><a href="{% url 'logout' %}?next={{ request.path }}">注销登录</a></button>
  18. <button class="btn btn-default"><a href="{% url 'password_change' %}?next={{ request.path }}">修改密码</a></button>
  19. {% else %}
  20. <p>你还没有登录,请
  21. <button class="btn btn-default"><a href="{% url 'login' %}?next={{ request.path }}">登录</a></button>
  22. 或者
  23. <button class="btn btn-default"><a href="{% url 'users:register' %}?next={{ request.path }}">注册</a></button>
  24. </p>
  25. {% endif %}
  26. </div>
  27. </div>
  28. </div>
  29. </body>
  30. </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。

  1. <!DOCTYPE html>
  2. <html lang="zh-cn">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="x-ua-compatible" content="ie=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  7. <title>修改密码</title>
  8. <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
  9. <style>
  10. .errorlist {
  11. color: red;
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <div class="flex-center">
  17. <div class="container">
  18. <div class="flex-center">
  19. <div class="unit-1-2 unit-1-on-mobile">
  20. <h1><a href="{% url 'index' %}">Django Auth Example</a></h1>
  21. <h3>修改密码</h3>
  22. <form class="form" action="{% url 'password_change' %}" method="post">
  23. {% csrf_token %}
  24. {{ form.non_field_errors }}
  25. {% for field in form %}
  26. {{ field.label_tag }}
  27. {{ field }}
  28. {{ field.errors }}
  29. {% if field.help_text %}
  30. <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
  31. {% endif %}
  32. {% endfor %}
  33. <button type="submit" class="btn btn-primary btn-block">确认修改</button>
  34. </form>
  35. </div>
  36. </div>
  37. </div>
  38. </div>
  39. </body>
  40. </html>
  1. <!DOCTYPE html>
  2. <html lang="zh-cn">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="x-ua-compatible" content="ie=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  7. <title>密码修改成功</title>
  8. <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
  9. </head>
  10. <body>
  11. <div class="flex-center">
  12. <div class="container">
  13. <div>
  14. <h1 class="logo"><a href="{% url 'index' %}">Django Auth Example</a></h1>
  15. <p>密码修改成功!</p>
  16. </div>
  17. </div>
  18. </div>
  19. </body>
  20. </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 :

  1. <form class="form" action="{% url 'password_reset' %}" method="post">
  2. {% csrf_token %}
  3. {{ form.non_field_errors }}
  4. {% for field in form %}
  5. {{ field.label_tag }}
  6. {{ field }}
  7. {{ field.errors }}
  8. {% if field.help_text %}
  9. <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
  10. {% endif %}
  11. {% endfor %}
  12. <button type="submit" class="btn btn-primary btn-block">提交</button>
  13. </form>

    password_reset_confirm.html

  1. <form class="form" method="post">
  2. {% csrf_token %}
  3. {{ form.non_field_errors }}
  4. {% for field in form %}
  5. {{ field.label_tag }}
  6. {{ field }}
  7. {{ field.errors }}
  8. {% if field.help_text %}
  9. <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
  10. {% endif %}
  11. {% endfor %}
  12. <button type="submit" class="btn btn-primary btn-block">提交</button>
  13. </form>

    

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

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

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

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

  1. <form class="form" action="{% url 'login' %}" method="post">
  2. {% csrf_token %}
  3. {{ form.non_field_errors }}
  4. {% for field in form %}
  5. {{ field.label_tag }}
  6. {{ field }}
  7. {{ field.errors }}
  8. {% if field.help_text %}
  9. <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
  10. {% endif %}
  11. {% endfor %}
  12. <button type="submit" class="btn btn-primary btn-block">登录</button>
  13. <input type="hidden" name="next" value="{{ next }}"/>
  14. </form>

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

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

    3、扩展

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

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

  1. from .models import User
  2. class EmailBackend(object):
  3. def authenticate(self, request, **credentials):
  4. # 要注意登录表单中用户输入的用户名或者邮箱的 field 名均为 username
  5. email = credentials.get('email', credentials.get('username'))
  6. try:
  7. user = User.objects.get(email=email)
  8. except User.DoesNotExist:
  9. pass
  10. else:
  11. if user.check_password(credentials["password"]):
  12. return user
  13. def get_user(self, user_id):
  14. """
  15. 该方法是必须的
  16. """
  17. try:
  18. return User.objects.get(pk=user_id)
  19. except User.DoesNotExist:
  20. return None

       配置settings.py:

  1. AUTHENTICATION_BACKENDS = (
  2. 'django.contrib.auth.backends.ModelBackend',
  3. 'users.backends.EmailBackend',
  4. )

 

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/71687
推荐阅读
相关标签
  

闽ICP备14008679号