[Django] Django(九) 用户认证

Django中的用户认证概述

Django带有一个用户认证系统,它负责处理用户账户、组、权限以及用户会话cookie。认证系统包括认证和授权(authentication 和 antuorization),认证是对一个系统声明的用户进行验证,授权是决定哪个已经认证的用户允许做什么。认证系统包括:

  • 用户(Users)
  • 权限(Permissions)
  • 用户组(Groups)
  • 一个可配置的密码散列系统
  • 表单和查看工具,用于登录用户或限制内容
  • 可插入的后端系统
  • *

安装

认证在django.contrib.auth包中作为Django contrib模块捆绑在一起。 默认情况下,所需的配置已包含在由django-admin startproject生成的settings.py中,这些配置由INSTALLED_APPS设置中列出的两个项目组成:

  • 'django.contrib.auth':包含认证框架的核心,以及它的默认模型。
  • 'django.contrib.contenttypes':是Django内容类型系统,它允许权限与创建的模型相关联。

1.User对象

User对象是认证系统的核心, 它代表访问网站的人,可以用于启用限制访问、注册用户配置文件、管理创建者和内容等。在认证框架中,User对象只有一个类:django.contrib.auth.models.User,超级用户或管理员用户是仅仅具有一些特殊属性的用户,而不是不同的User类。默认主要属性有:
username:
passoword:
email:
first_name:
last_name:

创建用户

创建用户最直接的方式是通过create_user()函数:

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', '[email protected]', 'johnpassword')

# At this point, user is a User object that has already been saved
# to the database. You can continue to change its attributes
# if you want to change other fields.
>>> user.last_name = 'Lennon'
>>> user.save()

create_user(username, email=None, password=None, **extra_fields)

创建超级用户

通过如下命令创建超级用户:

python manage.py createsuperuser

更改密码

Django中不会存储原始文本密码,而是一个hash值,因此不能直接操作User对象的password属性,Django提供了set_passoword()方法可以对密码进行修改:

>>> from django.contrib.auth.models import User
>>> u = User.objects.get(username='john')
>>> u.set_password('new password')
>>> u.save()

验证用户

使用authenticate()方法来验证用户,该方法原型如下:

authenticate(request=None, **credentials)

在验证时,如需要传入一个凭证作为关键字参数,默认使用usernamepassword,验证时在每个认证后端列表中检查,如果有效,返回该User对象,否则抛出PermissionDenied,并返回None,可以如下形式来验证用户:

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
    # A backend authenticated the credentials
else:
    # No backend authenticated the credentials

2.自定义User

在项目开发中,一般不会使用User,而是自定义一个User模型,可以扩充用户字段如:

from django.contrib.auth.models import AbstractUser


class UserProfiles(AbstractUser):
    GENDER = (
        ('male', u'男'),
        ('female', u'女'),
    )
    nickname = models.CharField(max_length=20)
    birthday = models.DateField(null=True, blank=True)
    image = models.ImageField(upload_to='upload/image/%Y/%m')
    gender = models.CharField(choices=GENDER)
    address = models.CharField(max_length=100)

现在自定义了一个UserProfile模型,当执行python manage.py makemigrations时,出现错误:

auth.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'UserProfiles.g
roups'.

这是因为,在自定义好用户后,还需要配置一下AUTH_USER_MODEL参数,如果不显式配置该参数,则默认值为auth.User,配置如下:

AUTH_USER_MODEL = 'users.UserProfiles'

这里需要注意,在配置的时候不是users.models.UserProfiles,而直接是app.class的形式

自定义User时出现的一些错误

1.对于ImageField字,需要安装Pillow:
pip install Pillow
2.出现如下异常:

ValueError: Invalid model reference ‘users.models.UserProfiles’. String model references must be of the form ‘app_la
bel.ModelName’.

这是因为将AUTH_USER_MODEL值配置错误,如 常见的这种错误配置:
AUTH_USER_MODEL=users.models.UserProfiles,正确的应该为:
AUTH_USER_MODEL=users.UserProfiles;
3.出现如下异常:

django.db.migrations.exceptions.InconsistentMigrationHistory:
Migration admin.0001_initial is applied before its dep
endency users.0001_initial on database ‘default’.
这是因为原来创建了auth.user表有依赖,删除表后重新创建一次即可。

3.Web请求的认证

Django使用session和中间件将认证功能系统挂到请求对象上,每次请求时都提供了requset.user属性,代表当前的用户,如果当前用户没有登录,该属性将被设置为一个AnonymousUser实例,可以通过is_authenticated属性进行判断:

if request.user.is_authenticated:
    # Do something for authenticated users.
    ...
else:
    # Do something for anonymous users.
    ...

User.is_authenticated是一个只读属性,返回值一直为True,与AnonymousUser.is_authenticated相反,它始终为False

用户登录

在视图中登录用户,使用login()函数进行登录,该函数如下:
login(request, user, backend=None),第一个参数为request对象,第二个参数为user对象。login()函数使用Django的session框架,会将用户的ID保存在session中,登录示例如下:

from django.contrib.auth import authenticate, login

def my_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(request, username=username, password=password)
    if user is not None:
        login(request, user)
        # Redirect to a success page.
        ...
    else:
        # Return an 'invalid login' error message.
        ...

用户登出

如果要退出用户,使用logout()函数,该函数只带有一个request参数。示例如下:

from django.contrib.auth import logout

def logout_view(request):
    logout(request)
    # Redirect to a success page.

在注销登录时需要注意:

  • 1.如果没有用户登录,使用logout()时也不会抛出任何异常;
  • 2.当使用logout()时,session中的数据将会被清空。

限制登录用户访问

使用is_authenticated

可以通过is_authenticated属性来限制用户的访问:

from django.conf import settings
from django.shortcuts import redirect

def my_view(request):
    if not request.user.is_authenticated:
        return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
    # ...

如果是当前已登录用户,则is_authenticated返回值永远为True,如果没有登录,则该返回值为False。

使用login_required装饰器

还可以通过@login_required进行验证,如下所示:

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    ...

login_required()函数原型如下:
login_required(redirect_field_name='next', login_url=None),它做了以下工作:

  • 如果当前没有用户登录,则会跳转到settings.LOGIN_URL中,并将当前的url绝对路径存储在一个next的字符串中;
  • 如果用户已登录,则正常执行view逻辑。

第一个参数redirect_field_name可以指定一个字符串来替换next
第二个参数login_url用于指定要跳转的路径,如果指定,则不会再跳转到settings.LOGIN_URL中。

猜你喜欢

转载自blog.csdn.net/fightfightfight/article/details/80186461
今日推荐