当前位置:   article > 正文

Django的身份认证系统_django身份验证

django身份验证

 

1 . 在Django中使用身份认证系统

Django的身份认证系统实际上是一个app,该app叫做django.contrib.auth,它在django contrib模块下

使用时只需要在setting.py文件的INSTALLED_APPS中添加:'django.contrib.auth' 即可

身份认证系统包括以下内容:

  • 用户
  • 权限:标志指定用户是否可以执行某项任务。
  • 组:向多个用户应用标签和权限的通用方法。
  • 可配置的密码散列系统
  • 用于登录用户或限制内容的表单和视图工具
  • 可插拔的后端系统

该身份认证系统包含密码强度检查、登陆限制、第三方身份验证、对象级权限设置

 

2. 添加与Django身份认证系统相关联的app

注意:使用身份认证系统时,一定要添加django.contrib.contenttypes这个app

这个app的叫做内容类型系统,它将允许身份认证系统与我们创建的模型相关联

也就是说身份认证系统与我们创建的模型需要通过内容类型系统进行处理

 

3. 添加与身份认证系统相关联的中间件

添加完这两个app后,还要在中间件中添加相关内容,即在setting.py文件的MIDDLEWARE中添加以下内容:

  • SessionMiddleware:session中间件,用来管理请求会话
  • AuthenticationMiddleware:身份验证中间件,用来使用户和请求相关联

总的来说身份认证系统使用了2个app,2个中间件

然后执行python manage.py migrate命令,数据库就会创建权限、用户、组相关的表结构

此时,我们可以执行 python manage.py createsuperuser 命令创建超级用户,然后启动django项目

访问:http://127.0.0.1:8000/admin/ 这个网址,对用户进行管理

注意:后台管理模块依赖于 django.contrib.admin 这个app

 

4. 身份认证系统中的密码加密

django默认使用PBKDF2进行密码存储,该密码机制非常安全,如果想要使用其他密码机制,则要在setting文件中修改即可,

以下是django提供的密码机制:

  1. [
  2. 'django.contrib.auth.hashers.PBKDF2PasswordHasher',
  3. 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
  4. 'django.contrib.auth.hashers.Argon2PasswordHasher',
  5. 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
  6. 'django.contrib.auth.hashers.BCryptPasswordHasher',
  7. 'django.contrib.auth.hashers.SHA1PasswordHasher',
  8. 'django.contrib.auth.hashers.MD5PasswordHasher',
  9. 'django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher',
  10. 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher',
  11. 'django.contrib.auth.hashers.CryptPasswordHasher',
  12. ]

对应的python算法是:

  1. pbkdf2_sha256
  2. pbkdf2_sha1
  3. argon2
  4. bcrypt_sha256
  5. bcrypt
  6. sha1
  7. md5
  8. unsalted_sha1
  9. unsalted_md5
  10. crypt

下面的代码是修改默认的密码机制,首先要在setting.py中添加下面的内容,

然后修改PASSWORD_HASHERS数组中下标为【0】的的数据,下标为0的指的就是密码保存时的加密算法:

  1. PASSWORD_HASHERS = [
  2. 'django.contrib.auth.hashers.PBKDF2PasswordHasher',
  3. 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
  4. 'django.contrib.auth.hashers.Argon2PasswordHasher',
  5. 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
  6. ]

 将上述的PBKDF2修改为MD5

  1. PASSWORD_HASHERS = [
  2. 'django.contrib.auth.hashers.MD5PasswordHasher',
  3. 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
  4. 'django.contrib.auth.hashers.Argon2PasswordHasher',
  5. 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
  6. ]

这里要说明一下DJango加密数据后的存储规则,其中$是分隔符:

<algorithm>$<iterations>$<salt>$<hash>
  • 第一个成员是散列算法,指的是md5,pbkdf2之类
  • 第二个成员是迭代次数(工作因子),跟君算法不同可以是字符串或数字
  • 第三个成员是随机盐
  • 第四个是密码哈希

两个不同的算法生成的结果如下,前两条是用pbkdf2加密的,后两条是md5:

启动Django,使用admin后台管理系统,添加用户,就能查看该用户的加密后的密码

Django会按照你在setting中的配置生成指定规则的密码,上面已说过

 

当然,django的密码加密不仅于此,还能将旧系统中的老密码重新进行加密升级,这个升级过程称之为包装

即将已有用户的以sha1加密的密码包装升级为PBKDF2加密的密码,这个升级过程和用户的登录无关

这一块用的人较少,仅说明一下,想看具体内容请访问官方文档:Django官方文档

 

 5. 身份认证系统中的用户密码修改

密码修改有两种,一种是不需要原密码进行修改,一种是需要原密码进行修改

不需要原密码进行修改有下面三种方式:

  • admin后台管理系统
  • python manage.py changepassword 修改
  • 通过自定义视图修改

 admin修改如下图:

 命令行修改方式如下:

 在Views.py视图中修改方式如下:

  1. def mysql(request):
  2. template = loader.get_template('app_Mysql/table.html')
  3. context = {
  4. 'latest_question_list': {'xxx': 123},
  5. }
  6. from django.contrib.auth.models import User
  7. u = User.objects.get(username='zhangsan')
  8. u.set_password('zhangsan66666')
  9. u.save()

需要身份验证修改密码的方式如下:

Django的身份验证除了可以使用自带的身份验证,也可以使用自定义的身份验证

下面是使用自带的身份验证:

  1. def mysql(request):
  2. template = loader.get_template('app_Mysql/table.html')
  3. context = {
  4. 'latest_question_list': {'xxx': 123},
  5. }
  6. # from django.contrib.auth.models import User
  7. # u = User.objects.get(username='zhangsan')
  8. # u.set_password('zhangsan66666')
  9. # u.save()
  10. from django.contrib.auth import authenticate
  11. user = authenticate(username='zhangsan', password='zhangsan66666')
  12. if user is not None:
  13. print('账户、密码输入正确')
  14. else:
  15. print('账户、密码输入不正确')
  16. return HttpResponse(template.render(context,request))

authenticate会根据获得的用户密码,去【检查】【配置的】【身份认证后端】,并返回一个是否有效的User用户(,假如配置了多个认证后端的话,检查过程会挨个检查认证后端,)

如果无效则返回None,有效则返回该用户

这里说明一下什么是身份认证后端:

身份认证后端:用于与【用户模型Model】相关联的【存储用户名和密码】的【一组服务】,称之为验证后端

即这个后端和用户模型挂钩,且为这个用户模型提供了相关验证服务

既然是Django提供的服务,那么我们就可以对这个服务进行定制、修改、替换

例如:公司已经存在一个LDAP,可以为每个员工存储用户名和密码,如果用户在LDAP和基于Django的应用程序中有单独的帐户,那么网络管理员和用户自己都会很麻烦。(用户登录时django会先验证该用户,然后再去ladp验证)

上面的情况就需要修改Django默认的认证后端,首先要在setting.py中添加下面的内容:

  1. AUTHENTICATION_BACKENDS =[
  2. 'django.contrib.auth.backends.ModelBackend'
  3. ]

然后对其进行替换,替换为我们自已定义的身份验证类。

也可以在这个数组中加入我们自定义的身份认证后端,加入后,程序会按照下面的方式进行,

先到默认的ModelBackend验证,然后再到我们加入的验证后端中验证,知道即可,不再赘述。

默认的验证类包含了用户身份验证、用户组、用户权限、权限组等,还是很全的

  1. from __future__ import unicode_literals
  2. from django.contrib.auth import get_user_model
  3. from django.contrib.auth.models import Permission
  4. UserModel = get_user_model()
  5. class ModelBackend(object):
  6. """
  7. Authenticates against settings.AUTH_USER_MODEL.
  8. """
  9. def authenticate(self, request, username=None, password=None, **kwargs):
  10. if username is None:
  11. username = kwargs.get(UserModel.USERNAME_FIELD)
  12. try:
  13. user = UserModel._default_manager.get_by_natural_key(username)
  14. except UserModel.DoesNotExist:
  15. # Run the default password hasher once to reduce the timing
  16. # difference between an existing and a non-existing user (#20760).
  17. UserModel().set_password(password)
  18. else:
  19. if user.check_password(password) and self.user_can_authenticate(user):
  20. return user
  21. def user_can_authenticate(self, user):
  22. """
  23. Reject users with is_active=False. Custom user models that don't have
  24. that attribute are allowed.
  25. """
  26. is_active = getattr(user, 'is_active', None)
  27. return is_active or is_active is None
  28. def _get_user_permissions(self, user_obj):
  29. return user_obj.user_permissions.all()
  30. def _get_group_permissions(self, user_obj):
  31. user_groups_field = get_user_model()._meta.get_field('groups')
  32. user_groups_query = 'group__%s' % user_groups_field.related_query_name()
  33. return Permission.objects.filter(**{user_groups_query: user_obj})
  34. def _get_permissions(self, user_obj, obj, from_name):
  35. """
  36. Returns the permissions of `user_obj` from `from_name`. `from_name` can
  37. be either "group" or "user" to return permissions from
  38. `_get_group_permissions` or `_get_user_permissions` respectively.
  39. """
  40. if not user_obj.is_active or user_obj.is_anonymous or obj is not None:
  41. return set()
  42. perm_cache_name = '_%s_perm_cache' % from_name
  43. if not hasattr(user_obj, perm_cache_name):
  44. if user_obj.is_superuser:
  45. perms = Permission.objects.all()
  46. else:
  47. perms = getattr(self, '_get_%s_permissions' % from_name)(user_obj)
  48. perms = perms.values_list('content_type__app_label', 'codename').order_by()
  49. setattr(user_obj, perm_cache_name, set("%s.%s" % (ct, name) for ct, name in perms))
  50. return getattr(user_obj, perm_cache_name)
  51. def get_user_permissions(self, user_obj, obj=None):
  52. """
  53. Returns a set of permission strings the user `user_obj` has from their
  54. `user_permissions`.
  55. """
  56. return self._get_permissions(user_obj, obj, 'user')
  57. def get_group_permissions(self, user_obj, obj=None):
  58. """
  59. Returns a set of permission strings the user `user_obj` has from the
  60. groups they belong.
  61. """
  62. return self._get_permissions(user_obj, obj, 'group')
  63. def get_all_permissions(self, user_obj, obj=None):
  64. if not user_obj.is_active or user_obj.is_anonymous or obj is not None:
  65. return set()
  66. if not hasattr(user_obj, '_perm_cache'):
  67. user_obj._perm_cache = self.get_user_permissions(user_obj)
  68. user_obj._perm_cache.update(self.get_group_permissions(user_obj))
  69. return user_obj._perm_cache
  70. def has_perm(self, user_obj, perm, obj=None):
  71. if not user_obj.is_active:
  72. return False
  73. return perm in self.get_all_permissions(user_obj, obj)
  74. def has_module_perms(self, user_obj, app_label):
  75. """
  76. Returns True if user_obj has any permissions in the given app_label.
  77. """
  78. if not user_obj.is_active:
  79. return False
  80. for perm in self.get_all_permissions(user_obj):
  81. if perm[:perm.index('.')] == app_label:
  82. return True
  83. return False
  84. def get_user(self, user_id):
  85. try:
  86. user = UserModel._default_manager.get(pk=user_id)
  87. except UserModel.DoesNotExist:
  88. return None
  89. return user if self.user_can_authenticate(user) else None
  90. class AllowAllUsersModelBackend(ModelBackend):
  91. def user_can_authenticate(self, user):
  92. return True
  93. class RemoteUserBackend(ModelBackend):
  94. """
  95. This backend is to be used in conjunction with the ``RemoteUserMiddleware``
  96. found in the middleware module of this package, and is used when the server
  97. is handling authentication outside of Django.
  98. By default, the ``authenticate`` method creates ``User`` objects for
  99. usernames that don't already exist in the database. Subclasses can disable
  100. this behavior by setting the ``create_unknown_user`` attribute to
  101. ``False``.
  102. """
  103. # Create a User object if not already in the database?
  104. create_unknown_user = True
  105. def authenticate(self, request, remote_user):
  106. """
  107. The username passed as ``remote_user`` is considered trusted. This
  108. method simply returns the ``User`` object with the given username,
  109. creating a new ``User`` object if ``create_unknown_user`` is ``True``.
  110. Returns None if ``create_unknown_user`` is ``False`` and a ``User``
  111. object with the given username is not found in the database.
  112. """
  113. if not remote_user:
  114. return
  115. user = None
  116. username = self.clean_username(remote_user)
  117. # Note that this could be accomplished in one try-except clause, but
  118. # instead we use get_or_create when creating unknown users since it has
  119. # built-in safeguards for multiple threads.
  120. if self.create_unknown_user:
  121. user, created = UserModel._default_manager.get_or_create(**{
  122. UserModel.USERNAME_FIELD: username
  123. })
  124. if created:
  125. user = self.configure_user(user)
  126. else:
  127. try:
  128. user = UserModel._default_manager.get_by_natural_key(username)
  129. except UserModel.DoesNotExist:
  130. pass
  131. return user if self.user_can_authenticate(user) else None
  132. def clean_username(self, username):
  133. """
  134. Performs any cleaning on the "username" prior to using it to get or
  135. create the user object. Returns the cleaned username.
  136. By default, returns the username unchanged.
  137. """
  138. return username
  139. def configure_user(self, user):
  140. """
  141. Configures a user after creation and returns the updated user.
  142. By default, returns the user unmodified.
  143. """
  144. return user
  145. class AllowAllUsersRemoteUserBackend(RemoteUserBackend):
  146. def user_can_authenticate(self, user):
  147. return True

了解更相信的内容,看官方文档:官方文档---身份认证后端

6. 用户的权限缓存

Django默认的ModelBackend会在用户请求登陆时获取该用户的相应权限,然后进行缓存,该缓存直至用户会话结束,否则不会刷新。

如果在页面上对该用户的权限做出了修改并且要求该用户新修改的权限立即生效,那么就需要重新获取该用户的相关权限

下面是获取用户权限的方法例子:

  1. from django.contrib.auth.models import Permission, User
  2. from django.contrib.contenttypes.models import ContentType
  3. from django.shortcuts import get_object_or_404
  4. from myapp.models import BlogPost
  5. def user_gains_perms(request, user_id):
  6. user = get_object_or_404(User, pk=user_id)
  7. # any permission check will cache the current set of permissions
  8. user.has_perm('myapp.change_blogpost')
  9. content_type = ContentType.objects.get_for_model(BlogPost)
  10. permission = Permission.objects.get(
  11. codename='change_blogpost',
  12. content_type=content_type,
  13. )
  14. user.user_permissions.add(permission)
  15. # Checking the cached permission set
  16. user.has_perm('myapp.change_blogpost') # False
  17. # Request new instance of User
  18. # Be aware that user.refresh_from_db() won't clear the cache.
  19. user = get_object_or_404(User, pk=user_id)
  20. # Permission cache is repopulated from the database
  21. user.has_perm('myapp.change_blogpost') # True
  22. ...

7. 用户退出操作

添加相应的url,然后添加对应的views中添加以下内容即可:

  1. #创建自定义的View,用来封装返回结果使用
  2. class ResponseResult_View(View):
  3. def __init__(self):
  4. self.code = 201
  5. self.message = '操作成功'
  6. self.data = None
  7. def get_result(self):
  8. return {'code': self.code, 'message': self.message, 'data': self.data}
  9. # 用户退出
  10. class User_logout(ResponseResult_View):
  11. @logging(level='INFO')
  12. def get(self, request):
  13. logout(request)
  14. return render(request, "app_User/login.html")

8. 未验证用户的重定向操作

重定向使用装饰器能够轻松解决指定视图用户访问时的验证问题

下面是django的默认装饰器login_required,该装饰器可以无参,也可以有参:

无参情况,在setting设置跳转:

  1. #无参情况
  2. #setting文件内容,需要指定LOGIN_URL
  3. 未登录,重定向页面
  4. LOGIN_URL = '/user/login'
  5. #主页
  6. @login_required
  7. def User_main(request):
  8. return render(request, 'app_User/main.html',)

有参情况,直接在装饰器参数中指定跳转:

  1. @login_required(login_url='/user/login')
  2. def User_main(request):
  3. return render(request, 'app_User/main.html',)

注意:user/login要配置在app的urls中,如下图:

  1. from django.conf.urls import url
  2. from app_User import views
  3. urlpatterns = [
  4. url(r'^main$', views.User_main, name='main'),
  5. url(r'^login$', views.User_login.as_view(), name='login'),
  6. url(r'^logout$', views.User_logout.as_view(), name='logout'),
  7. ]

至于登录模块的验证的更多方法,请参考:官方文档authenticate

 

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

闽ICP备14008679号