当前位置:   article > 正文

Django 认证系统_django authorization

django authorization

该博客翻译于使用Django 认证系统
Django 认证提供了认证(authentiaction)和授权(authorization)两种功能, 由于这两种功能在某些程度上有相互的联系。所以Django的认证通常被用做认证系统。


User 对象

在认证系统中User对象是其核心部分。它通常表示与你的站点交互的用户,并且User对象还用于权限控制,注册用户,关联内容创建者等功能。 在Django的认证系统中,只有一种类型的用户,也就是说’superusers‘和管理员’staff‘用户是具有特定属性集的用户,而不是不同类型的User对象。

默认的User对象有以下的基本字段:

  • username
  • password
  • email
  • first_name
  • last_name

详细的API请参照 完整的API文档,以下的文档,偏向于特定的任务。


创建用户(users)

创建users最直接的方法就是使用create_user() 这个辅助函数。

from django.contrib.auth.models import User
user = User.object.create_user('john', 'lennon@thebeatles.com', 'password')
# 到这里,user 这一个User对象已经保存于数据库中了。
# 你可以继续修改它的属性。
# 例如修改user的last_name
user.last_name = 'Lennon'
user.save()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果你在setting文件中的INSTALL_APP中配置了admin,你也可以通过admin来交互式地管理用户


创建超级用户(superusers)

使用createsuperuser来创建超级用户:
$ python manage.py createsuperuser --username=joe --email=joe@example.com

然后该命令将提示你输入密码,输入密码后,该用户将会被立即创立, 如果你忘记 打入 –username–email参数,该命令将提示你输入这些值。


修改密码

Django不会再user模型上存储密码的明文,而是一个哈希值,(详细内容请见文档:Django 是如何处理密码的), 因此,请不要直接对user对象的password属性进行操作。这也是我们使用create_user()这个辅助函数来创建用户的原因。

若要修改用户的密码,有以下几种选择:
1. 使用命令manage.py changepassword *username*该命令提供一种从命令行修改User密码的方法。它提示你修改一个给定user的密码,你必须输入两次密码。如果输入的两次密码相同,给定user的密码将会立马被修改成新的密码。如果你没有提供user ,命令将会尝试修改与当前系统用户同名的user的密码。
2. 使用set_password() 方法

>>> from django.contrib.auth.models import User
>>> u = User.object.get(username='john')
>>> u.set_password('new password')
>>> u.save()
  • 1
  • 2
  • 3
  • 4

同样的,如果安装了admin,你也可以在admin的认证系统页面修改用户的密码.

如果启用了SessionAuthenticationMiddleware, 修改密码将会使该用户的所有会话失效


认证用户

authenticate(**credentials)

使用authenticate()方法来认证一个给定的用户名(username)和密码(password)。该函数以关键字参数的形式接受认证的凭证,默认配置的关键字是usernamepassword。如果密码和用户名匹配,该函数返回一个User对象,否则,该函数返回None,例如:

from django.contrib.auth import authenticate
user = authenticate(username='john',password='secret'
if user is not None:
    # 用户通过验证
    if user.is_active:
        print("User is valid, active and authenticated")
    else:
        print("The password is valid, but the account has been disabled!")
else:
    print("The username and password were incorrect.")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

关于is_active属性,详细信息请参考上文的完全API手册。


权限和授权

Django 自带一个简单的权限系统,为特定的用户和用户组分配不同的权限提供了一种方法。
它在Django的admin站点中使用。也欢迎你在自己的代码中使用这个权限系统。
在Django的admin中使用如下的权限:

  • 对某个对象的类型拥有”添加(add)”权限的用户,才能够访问”add”表单,并且添加一个该类型的对象(译注:例如,某个用户对Brand这个类型拥有add的权限, 该用户,才能够访问add表单并且添加一个Brand的对象)
  • 对某个对象的类型拥有”修改(change)”权限的用户,才能够查看修改列表,”change”表单,或修改一个对象。
  • 对某个对象的类型拥有“删除(delete)”权限的用户,才能够删除对象。

不仅如此,不仅可以为每个类型设置不同的权限,而且可以为特定的对象设置不同的权限。为了给统一中类型的不同的对象设置不同的权限,我们可以使用ModelAdmin类提供的方法:
has_add_permision()
has_change_permission()
has_delete_permission()

User的对象拥有两个多对多的字段:groupsuser_permissions,User对象可以像任何其他Django 模型一样访问与它相关连的对象:

myuser.groups = [group_list]
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions = [permission_list]
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

默认的权限

当在Django配置文件的INSTALLED_APP中添加django.contrib.auth时,Django将会为所有安装应用中定义的Django模型创建默认的权限——add,change和delete

在往INSTALLED_APP中添加django.contrib.auth的第一次迁移(migrate)中,Django 将会为INSTALLED_APP 中所有的应用定义的模型创建默认权限。在后续添加的应用中,当运行manage.py migrate时,Django也会为新增的应用创建默认权限。

假设你有一个app_lablefoo的应用和名为Bar的模型, 用下面的代码来测试你能够使用的基本权限:

  • add: user.has_perm(‘foo.add_bar’)
  • change:user.has_perm(‘foo.change_bar’)
  • delete: user.has_perm(‘foo.delete_bar’)

用户组(Group)

django.contrib.auth.models.Group模型是用户分类的一种通用的方式,通过这种方式你可以给这些用户分配不同的权限,或者设置不同的标签。一个用户可以属于多个用户组

在用户组中的用户拥有该用户组被授予的权限。例如用户组Site editors拥有can_edir_home_page的权限,那么在该用户组中的所有用户,都拥有该权限。

出了权限之外,用户组还是给分类用户分配标签,添加功能的便捷方法。例如,你可以创建一个叫做”Special users“的用户组,只有在改组中的用户才能够访问会员的页面。


用代码的方法创建用户权限

虽然在模型的元类中定义自定义权限,但是你也可以直接创建权限。例如你可以为myapp的BlogPost应用创建can_publish权限:

from myapp.models import BlogPost
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.create(
    codename='can_publish',
    name='Can Publish Posts',
    content_type=content_type,
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

然后该权限可以通过user的user_permissions属性分配给一个用户,也可以通过Group的permission属性分配一个用户组。


权限的缓存

ModelBackend在第一次需要访问User对象的权限时会对权限进行缓存。由于对新添加的权限并不会立即检查,所以这种做法对request-response 循环是非常有利的(例如在admin中)。如果你想要在添加新的权限后马上在测试或视图检查他们,最简单的解决办法是从数据库中重新获取User:

from django.contrib.auth.models import Permission, User
from django.shortcuts import get_object_or_404

def user_gains_perms(request, user_id):
    user = get_object_or_404(User, pk=user_id)
    # any permission check will cache the current set of permissions
    user.has_perm('myapp.change_bar')

    permission = Permission.objects.get(codename='change_bar')
    user.user_permissions.add(permission)

    # Checking the cached permission set
    user.has_perm('myapp.change_bar')  # False

    # Request new instance of User
    # Be aware that user.refresh_from_db() won't clear the cache.
    user = get_object_or_404(User, pk=user_id)

    # Permission cache is repopulated from the database
    user.has_perm('myapp.change_bar')  # True
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在web请求中的认证

Django 使用会话(sessions)和中间件来拦截request对象到认证系统中。

认证系统为每个请求(request)提供一个request.user属性来代表当前的用户。如果当前的用户仍未登录,该属性将会被设置为一个AnonymousUser的实例,否则该属性将会是一个User实例。

可以通过is_authenticated()方法来区分它们。例如:

if request.user.is_authenticated():
    # Do something for authenticated users.
    ...
else:
    # Do something for anonymous users.
    ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如何实现用户登录(log in)

如果你有一个认证了的用户,你想把它附带到当前的会话中, 这可以通过login()函数实现。

login(request, user)
  在视图中,登录用户使用login()函数,该函数接受两个参数,HttpRequest对象和User对象。login()函数在session中存入了用户的ID。
  注意,在匿名会话中设置的人和值都会在用户登录后被记录下来。
  一下是如何使用authenticate()login()的实例:

from django.contrib.auth import authenticate, login

def my_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(username=username, password=password)
    if user is not None:
        if user.is_active:
            login(request, user)
            # Redirect to a success page.
        else:
            # Return a 'disabled account' error message
            ...
    else:
        # Return an 'invalid login' error message.
        ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

  user对象必须是调用authenticate()方法获得的。如果试图登入一个直接从数据库中取出的用户,将会抛出一个错误.

如何实现用户登出(log out)

 要实现用户登出,可以在试图中使用logout()函数,该函数接受一个HttpRequest的对象作为参数。例如:

from django.contrib.auth import logout

def logout_view(request):
    logout(request)
    # 重定向到另一页面
  • 1
  • 2
  • 3
  • 4
  • 5

注意:logout()在用户登出失败的情况下并不会抛出任何错误。
为了防止在同一浏览器后续登陆的用户获取到之前登陆用户的数据,在你调用logout()函数登出用户时,当前请求(request)的会话的数据将会被完全清空。如果在用户登出后你想要在session中存放任何数据,那么请在调用django.contrib.auth.logout()后执行存放数据的操作。


只允许登陆的用户访问

原始的方法

限制登陆的用户访问页面最简单和原始的方法,是检查request.user.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))
    # ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用login_required decorator

login_required(redirect_field_name=’next’, login_url=None)
你可以使用login_required()装饰器,作为一种快捷方式:

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    # ...
  • 1
  • 2
  • 3
  • 4
  • 5

装饰器login_required()完成了下面的内容。

  • 若用户没有登陆,则重定向到配置文件中LOGIN_URL指向的路径,并且把当前请求的绝对路径作为查询参数传递到登陆页面。例如:/account/login/?next=/polls/3/
  • 若用户已经登陆,将正常的执行视图函数的内容,视图函数的代码可以安全地假设用户已经登陆。

默认情况下,用户在成功认证后应该被重定向到的路径存储在查询字符串的一个叫做”next”的参数中。如果你倾向于使用使用另一个名字作为该参数,login_required()带有一个可选的redirect_field_name参数:

from django.contrib.auth.decorators import login_required

@login_required(redirect_field_name='my_redirect_field')
def my_view(request):
    ...
  • 1
  • 2
  • 3
  • 4
  • 5

login_required()还接收一个可选的参数login_url

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/')
def my_view(request):
    # ...
  • 1
  • 2
  • 3
  • 4
  • 5

注意如果不指定login_url参数,那么你必须设置配置文件中的LOGIN_URL关联到你对应的登陆页面,

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

闽ICP备14008679号