使用django-allauth管理用户登录与注册

 django-allauth 是非常受欢迎的管理用户登录与注册的第三方 Django 安装包,django-allauth 集成了 local 用户系统 和 social 用户系统,其 social 用户系统 可以挂载多个账户。
django-allauth 能实现以下核心功能:

用户注册

用户登录

退出登录

第三方auth登录(微信,微博等)

邮箱验证

修改邮箱

修改密码

忘记密码,登录后邮箱发送密码重置链接

安装与配置

安装 django-allauth

allenlideMacBook-Pro:~ allen$ mkvirtualenv oauth
(oauth) allenlideMacBook-Pro:~ allen$ pip install django
(oauth) allenlideMacBook-Pro:~ allen$ pip install django-allauth

创建 Django 项目

使用django-allauth管理用户登录与注册_第1张图片

项目基础配置

安装好后设置 oauth/settings.py,将allauth相关APP加入到INSTALLED_APP里去。对于第三方的providers,你希望用谁就把它加进去。值得注意的是allauth对于站点设置django.contrib.sites有依赖,你必需也把它加入进去,同时设置SITE_ID。

INSTALLED_APPS = [
    ...,
    # django-allauth 需要注册的 app
    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.weibo',
    'allauth.socialaccount.providers.github',
]

# 当出现 "SocialApp matching query does not exist" 这种报错的时候就需要更换这个ID
SITE_ID = 1

设置 BACKENDS 并提供用户登录验证的方法和用户登录后跳转的链接

# allauth 设置 BACKENDS
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'allauth.account.auth_backends.AuthenticationBackend',
)

# 设置登录和注册成功后重定向的页面,默认是 "/accounts/profile/"
LOGIN_REDIRECT_URL = "/accounts/profile/"

配置 django-allauth 其它选项

ACCOUNT_EMAIL_VERIFICATION = 'mandatory' # 强制注册邮箱验证(注册成功后,会发送一封验证邮件,用户必须验证邮箱后,才能登陆)
ACCOUNT_AUTHENTICATION_METHOD = "username_email"     # 登录方式(选择用户名或者邮箱都能登录)
ACCOUNT_EMAIL_REQUIRED = True           # 设置用户注册的时候必须填写邮箱地址
ACCOUNT_LOGOUT_ON_GET = False           # 用户登出(需要确认)

配置邮箱

EMAIL_HOST = "smtp.sina.com"
EMAIL_PORT = 25
EMAIL_HOST_USER = "[email protected]"
EMAIL_HOST_PASSWORD = "password"        # 这个不是邮箱密码,而是授权码
EMAIL_USE_TLS = True                    # 这里必须是 True,否则发送不成功
EMAIL_FROM = "[email protected]"         # 发件人
DEFAULT_FROM_EMAIL = "OPCoder 博客 " # 默认发件人(如果不添加DEFAULT_FROM_EMAIL字段可能会导致如下错误: 451, b'Sender address format error.', 'webmaster@localhost')

修改时区

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False

将 allauth 添加加到项目的 urls.py 中

from django.conf.urls import url, include

urlpatterns = [
    ...,
    url(r'^accounts/', include('allauth.urls')),
]

django-allauth 常见设置选项

  • ACCOUNT_AUTHENTICATION_METHOD (="username" | "email" | "username_email") 指定要使用的登录方法(用户名、电子邮件地址或两者之一)
  • ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS (=3) 邮箱确认邮件的截止日期(天数)
  • ACCOUNT_EMAIL_VERIFICATION (="optional") 注册中邮件验证方法: "强制(mandatory)"、 "可选(optional)" 或 "否(none)" 之一
  • ACCOUNT_EMAIL_CONFIRMATION_COOLDOWN (=180) 邮件发送后的冷却时间(以秒为单位)
  • ACCOUNT_LOGIN_ATTEMPTS_LIMIT (=5) 登录尝试失败的次数
  • ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT (=300) 从上次失败的登录尝试,用户被禁止尝试登录的持续时间
  • ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION (=False) 更改为True,用户一旦确认他们的电子邮件地址,就会自动登录
  • ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE (=False) 更改或设置密码后是否自动退出
  • ACCOUNT_LOGIN_ON_PASSWORD_RESET (=False) 更改为True,用户将在重置密码后自动登录
  • ACCOUNT_SESSION_REMEMBER (=None) 控制会话的生命周期,可选项还有: "False" 和 "True"
  • ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE (=False) 用户注册时是否需要输入邮箱两遍
  • ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE (=True) 用户注册时是否需要用户输入两遍密码
  • ACCOUNT_USERNAME_BLACKLIST (=[]) 用户不能使用的用户名列表
  • ACCOUNT_UNIQUE_EMAIL (=True) 加强电子邮件地址的唯一性
  • ACCOUNT_USERNAME_MIN_LENGTH (=1) 用户名允许的最小长度的整数
  • SOCIALACCOUNT_AUTO_SIGNUP (=True) 使用从社交账号提供者检索的字段(如用户名、邮件)来绕过注册表单
  • LOGIN_REDIRECT_URL (="/") 设置登录后跳转链接
  • ACCOUNT_LOGOUT_REDIRECT_URL (="/") 设置退出登录后跳转链接
  • ACCOUNT_LOGOUT_ON_GET (=True) 用户登出是否需要确认确认(True表示直接退出,不用确认;False表示需要确认)

生成数据库

python manage.py makemigrations
python manage.py migrate
python manage.py runserver

页面访问

  • 注册  http://127.0.0.1:8000/accounts/signup/
  • 登录  http://127.0.0.1:8000/accounts/login/
  • 注销  http://127.0.0.1:8000/accounts/logout/
  • 忘记密码  http://127.0.0.1:8000/accounts/password/reset/

用户注册
当注册成功后,用户会收到一封邮件来验证邮箱(使用邮箱强制验证),在你提交表单后,django-allauth会自动检测用户名和email是否已经存在。 使用django-allauth管理用户登录与注册_第2张图片
使用django-allauth管理用户登录与注册_第3张图片
邮箱验证
点击邮件中的链接,点击"确认"就可以验证邮箱了。
如果你不需要邮箱验证,只需要设置 ACCOUNT_EMAIL_VERIFICATION = 'none' 就可以了。 使用django-allauth管理用户登录与注册_第4张图片
使用django-allauth管理用户登录与注册_第5张图片
如果需要去掉邮件中的 "example.com",只需要在 admin后台 中改下 "显示名称" 就可以了。

# 创建超级用户,用于登陆后台页面
python manage.py createsuperuser

使用django-allauth管理用户登录与注册_第6张图片
重新注册, 检查邮件内容是否已经变更 使用django-allauth管理用户登录与注册_第7张图片

用户登录
使用django-allauth管理用户登录与注册_第8张图片

用户登出 使用django-allauth管理用户登录与注册_第9张图片

修改密码 使用django-allauth管理用户登录与注册_第10张图片

重置密码 使用django-allauth管理用户登录与注册_第11张图片

修改邮箱
使用django-allauth管理用户登录与注册_第12张图片

django-allauth 内置的 URLs

  • /accounts/signup [name='account_signup'] 注册
  • /accounts/login [name='account_login'] 登录
  • /accounts/logout [name='account_logout'] 登出
  • /accounts/password/change/ [name='account_change_password'] 修改密码(需登录)
  • /accounts/password/set/ [name='account_set_password'] 设置密码(用于邮件重置密码,不需要登录)
  • /accounts/social/ 社交账号

扩展用户模型

django-allauth 并没有提供展示和修改用户资料的功能,也没有对用户资料进行扩展,所以我们需要自定义用户模型来进行扩展。

创建 app 及配置

由于 django-allauth 已经占用了 account 这个 app,所以我们需要创建一个名叫 users 的 app,并将其加入 settings.py 配置文件的 INSTALL_APPS 中,同时把url也加入到项目的 ROOT URLs 中。

python manage.py startapp users
# settings.py

INSTALLED_APPS = [
    ...,
    'users',
    # django-allauth 需要注册的 app
    'django.contrib.sites',
    'allauth',
    ...,
]
# urls.py

from django.conf.urls import url, include

urlpatterns = [
    ...,
    url(r'^accounts/', include('allauth.urls')),
    url(r'^accounts/', include('users.urls')),
]

因为我们希望用户在登录或注册成功后,自动跳转到 "/accounts/profile/",我们可以加入(修改)如下代码

# settings.py

LOGIN_REDIRECT_URL = "/accounts/profile/"

创建用户模型及表单

# users/models.py

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


class UserProfile(AbstractUser):
    GENDER_CHOICE = (
        ('male', '男'),
        ('female', '女')
    )
    nick_name = models.CharField(max_length=20, verbose_name='昵称', null=True, blank=True)
    mobile = models.CharField(max_length=11, verbose_name='手机', null=True, blank=True)
    address = models.CharField(max_length=200, verbose_name='地址', null=True, blank=True)

    class Meta:
        verbose_name = '用户信息'
        verbose_name_plural = verbose_name
        ordering = ['-id']

    def __str__(self):
        return self.username
# users/forms.py

from django import forms
from .models import UserProfile

class ProfileForm(forms.ModelForm):
    '''从模型继承表单'''
    class Meta:
        model = UserProfile
        fields = ['nick_name', 'mobile', 'address']

创建自定义用户模型后, 需更改settings.py文件,指明使用的是自定义用户模型

AUTH_USER_MODEL = 'users.UserProfile'

创建视图并配置URLs

我们需要创建2个URLs和对应的视图来实现用户资料展示和用户资料编辑页面。

  • 个人资料URLs
# users/urls.py

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

app_name = 'users'
urlpatterns = [
    url(r'^profile/$', views.profile, name='profile'),
    url(r'^profile/change/$', views.change_profile, name='change_profile'),
]
  • 展示个人资料视图
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages

from .models import UserProfile
from .forms import ProfileForm


@login_required
def profile(request):
    '''展示个人资料'''
    user = request.user
    return render(request, 'users/profile.html', {'user':user})
  • 更新个人资料视图
# users/views.py

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages

from .models import UserProfile
from .forms import ProfileForm

@login_required
def change_profile(request):
    '''更新个人资料'''
    if request.method == 'POST':
        # instance参数表示用model实例来初始化表单,这样就可以达到通过表单来更新数据 
        form = ProfileForm(request.POST, instance=request.user)
        if form.is_valid():
            form.save()
            # 添加一条信息,表单验证成功就重定向到个人信息页面
            messages.add_message(request, messages.SUCCESS, '个人信息更新成功!')
            return redirect('users:profile')
    else:
        # 不是POST请求就返回空表单
        form = ProfileForm(instance=request.user)

    return render(request, 'users/change_profile.html', context={'form': form})

创建模板文件

  • 展示个人资料模板文件
# users/templates/users/profile.html




    
    个人资料




{% if messages %}
{% for message in messages %} {% endfor %}
{% endif %} {% if user.is_authenticated %} 修改资料 注销 {% endif %}

Welcome, {{ user.username }}

  • nick_name: {{ user.nick_name }}
  • mobile: {{ user.mobile }}
  • address: {{ user.address }}

由于修改个人资料需要处理表单, 我们可以安装 django-crispy-forms 插件来处理(美化)表单

# 安装 
pip install django-crispy-forms

# 加入 INSTALLED_APPS
INSTALLED_APPS = [
    ...,
    'allauth.socialaccount.providers.weibo',
    'allauth.socialaccount.providers.github',

    'crispy_forms',  # bootstrap 表单样式
]

# 配置表单插件使用的样式
CRISPY_TEMPLATE_PACK = 'bootstrap4'
  • 更新个人资料模板文件
# users/templates/users/change_profile.html

{% load crispy_forms_tags %}




    
    修改资料
    




{% if messages %}
{% for message in messages %} {% endfor %}
{% endif %} {% if user.is_authenticated %} 修改资料 注销 {% endif %}
> {% csrf_token %} {{ form|crispy }}

生成数据库

由于数据库已存在默认的用户表,使用自定义用户表进行migrate时, 应将数据库重置为初始状态,初始化成功后, 自定义用户表将会覆盖默认的用户表。

python manage.py makemigrations
python manage.py migrate

页面访问

python manage.py runserver
  • 注册并激活用户 使用django-allauth管理用户登录与注册_第13张图片
  • 登录(根据LOGIN_REDIRECT_URL设置,登录成功后跳转到"/accounts/profile"页面) 使用django-allauth管理用户登录与注册_第14张图片
  • 修改资料 使用django-allauth管理用户登录与注册_第15张图片
  • 更新资料后,重新访问个人资料页面
    使用django-allauth管理用户登录与注册_第16张图片

代码优化

  • 提示用户邮箱未通过验证 当用户设置 ACCOUNT_EMAIL_VERIFICATION='none',表示用户不需要进行邮箱验证也可以进行登录,这时候,我们可以为用户添加一条提示信息(如邮箱未验证),提醒用户进行邮箱验证。
# users/models.py 定义 "邮箱验证" 方法

from django.db import models
from django.contrib.auth.models import AbstractUser
from allauth.account.models import EmailAddress


class UserProfile(AbstractUser):
    ...,

    def email_verified(self):
        if self.is_authenticated:
            result = EmailAddress.objects.filter(email=self.email)
            if len(result):
                return result[0].verified
        else:
            return False
# 直接在数据中修改 "account_emailaddress.verified=0",表示邮箱未验证

SQL> update account_emailaddress t set t.verified = 0;
# 修改 settings.py 文件 ACCOUNT_EMAIL_VERIFICATION = 'none',表示邮箱未验证,也可以登录

ACCOUNT_EMAIL_VERIFICATION = 'none'
# users/templates/users/profile.html 添加消息(验证邮箱)


{% if messages %}
{% for message in messages %} {% endfor %}
{% endif %}

用户未验证邮箱(显示"验证邮箱") 使用django-allauth管理用户登录与注册_第17张图片
用户已验证邮箱(不会显示"验证邮箱") 使用django-allauth管理用户登录与注册_第18张图片注: 邮箱验证消息提示,可以只显示在用户登录成功后页面。

  • 修改个人资料(如手机)添加校验规则 在修改个人资料的时候,我们并未对手机号进行正则校验,用户随便输入一个手机号都可以进行修改,我们可以对表单添加校验规则来规范用户的输入。

第三方 auth 登录

github 账号

  • 将第三方服务商 providers.github 加入到 settings.py 配置文件的 INSTALLED_APP 中
INSTALLED_APPS = [
    ...,
    'allauth.socialaccount.providers.github',
]
  • 在github上申请一个OAuth App("settings" -> "Developer settings" -> "Register a new application") Github OAuth注册页面 使用django-allauth管理用户登录与注册_第19张图片
  • 申请完成 Oauth app 后,会得到 Client ID 和 Client Secret 使用django-allauth管理用户登录与注册_第20张图片
  • 点开站点管理,将example.com改为我们博客的域名,在开发环境下,我们用 http://127.0.0.1:8000/ 使用django-allauth管理用户登录与注册_第21张图片
  • 在 admin后台管理页面 点击 SOCIAL ACCOUNTS 下的 Social application,增加一个 application 使用django-allauth管理用户登录与注册_第22张图片
  • 使用 GitHub 登录 使用django-allauth管理用户登录与注册_第23张图片
  • 登录成功 使用django-allauth管理用户登录与注册_第24张图片

  • 使用GitHub作为第三方登录,关联成功后,不需要设置邮箱和用户名,数据库会记录邮箱和用户名 使用django-allauth管理用户登录与注册_第25张图片

baidu 账号

  • 将第三方服务商 providers.github 加入到 settings.py 配置文件的 INSTALLED_APP 中
INSTALLED_APPS = [
    ...,
    'allauth.socialaccount.providers.github',
]
  • 获取 Baidu 的 API Key 和 Secret Key 登录百度开发者中心 http://developer.baidu.com/,创建一个项目,百度会自动给你分配 API Key 和 Secret Key 使用django-allauth管理用户登录与注册_第26张图片
    使用django-allauth管理用户登录与注册_第27张图片
    使用django-allauth管理用户登录与注册_第28张图片
  • 应用创建好之后,还需要点击 "安全设置",设置回调URL,这样当百度授权登录完成后,可以跳转回自己的网站(回调的URL地址为: http://127.0.0.1:8000/accounts/baidu/login/callback/) 使用django-allauth管理用户登录与注册_第29张图片
  • 在 admin后台管理页面 点击 SOCIAL ACCOUNTS 下的 Social application,增加一个 application 使用django-allauth管理用户登录与注册_第30张图片注: 在开发环境中请确保 "sites" 的 "domain.name" 已经设置为 "127.0.0.1",而生产环境中, 可以设置为自己的域名。
  • 使用 Baidu 登录 使用django-allauth管理用户登录与注册_第31张图片
  • 使用 Baidu 作为第三方登录,关联成功后,还需要设置邮箱和用户名 使用django-allauth管理用户登录与注册_第32张图片
  • 登录成功 使用django-allauth管理用户登录与注册_第33张图片

美化表单

django-allauth 自带的模板是没有经过美化的,另外涉及到邮箱验证和各种消息也是固定的,所以我们就需要进行模板的美化以及邮箱验证和消息文本的修改。

  • 下载 django-allauth 模板和邮件文本文件 我们可以从 github 上将 django-allauth 的 /templates/account 文件夹拷贝至本地应用中(下载地址: https://github.com/pennersr/django-allauth/tree/master/allauth) 使用django-allauth管理用户登录与注册_第34张图片
  • 创建css文件,用于修改样式
# users/static/users/css/account.css

.secondaryAction {
    color: #868e96;
}
.secondaryAction:hover {
    text-decoration: none;
    color: #007bff;
}
.asteriskField {
    margin-left: .25rem;
    color: #dc3545;
}
#social-login .login-title {
    position: relative;
    display: block;
    margin-bottom:10px;
}
#social-login span {
    color:#999;
}
#social-login span:before,
#social-login span:after {
    position: absolute;
    top: 50%;
    background: #eee;
    width: 38%;
    height: 1px;
    content: '';
}
#social-login span:before {
    left:0;
}
#social-login span:after {
    right:0;
}
.fa-weibo {
    color: #e12f11;
    opacity: .8;
}
.fa-github {
    color: #333;
    opacity: .8;
}
.fa-weibo:hover,
.fa-github:hover {
    opacity: 1;
}
.btn-sm {
    padding:.2rem .7rem;
}
.change_profile .form-control,
.card-login .form-control {
    border-radius: 0;
}
.change_profile .alert,
.card-login .alert {
    border-radius: 0;
}
.change_profile .alert li,
.card-login .alert li {
    margin-bottom: .5rem;
}
.change_profile .alert ul,
.card-login .alert ul {
    padding-left:.5rem;
    margin-bottom: 0;
}
#profile-avatar .avatar {
    width:80px;
    padding: .25rem;
    background-color: #fff;
    border: 1px solid #dee2e6;
    border-radius: .25rem;
}
  • 在 settings.py 文件中配置模板文件位置
TEMPLATES = [
    {
        ...,
        'DIRS': [os.path.join(BASE_DIR, 'templates')],  # 模板文件
        'APP_DIRS': True,
        ...,
    },
]
  • 使用 bootstrap 美化表单,修改 base.html 使用 bootstrap 美化表单, 需要确认是否安装了 django-crispy-forms
# templates/account/base.html




    
    
    

    {% block head_title %}{% endblock %}

    
    
    



{% block message %}
    {% if messages %}
    
{% for message in messages %} {% endfor %}
{% endif %} {% endblock %} {% block base_content %}

{% block user_title %}账号管理{% endblock %}

{% endblock %} {% block extra_body %} {% endblock %}
  • 美化 login 登录页面
# templates/account/login.html

{% extends "account/base.html" %}

{% load i18n %}
{% load account socialaccount %}
{% load crispy_forms_tags %}

{% block head_title %}{% trans "Sign In" %}{% endblock %}

{% block content %}

{% endblock %}

在视图函数中,有些操作是需要用户在登录前提下才能进行的。

方法一:
采用request方法来得到用户是否登录信息:

if request.user.is_authenticated():
    ...
else:
    return render(requeset, 'login.html')

    1
    2
    3
    4

方法二:
在试图函数中继承一个基础类,可以判断用户是否登录。

在utils.py中定义一个基础类:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator


class LoginRequiredMixin(object):
    """
    判断用户是否登录
    """
    @method_decorator(login_required(login_url='/login/'))
    def dispatch(self, request, *args, **kwargs):
        return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

在编写视图函数时,继承该类:

from utils import LoginRequiredMixin

class CourseCommentView(LoginRequiredMixin, View):
    """
    课程评论
    """
    def get(self, request):
        pass

 

参考资料

https://django-allauth.readthedocs.io/en/latest/

第三方登录https://www.cnblogs.com/weixuqin/p/9330452.html

https://www.cnblogs.com/crime/p/11025823.html

你可能感兴趣的:(#,Django)