当前位置:   article > 正文

基于Django中间件的权限认证组件_django中间件权限验证不用每个函数都request_login

django中间件权限验证不用每个函数都request_login

用户权限认证组件包括权限model类和中间件类

model类介绍

Permission

权限类

权限基本信息包括title:权限名称 url:权限具体url

Role

角色类

角色类包括title:角色名称 permission:角色的权限

权限和角色多对多关系

用户类需要对Role类设置多对多映射

Whitelist

白名单类

白名单包括title:权限名称 url:权限具体url

白名单内存放的是系统放行不进行权限校验的url

NeedLogin

登录验证包括title:url标题 url:具体url

登录验证表存放的是需要登录才能进行操作或权限校验的url,如果没有登录则会重定向到登录页面

models.py

  1. from django.db import models
  2. class Permission(models.Model):
  3. '''
  4. 权限基本信息包括title:权限名称 url:权限具体url
  5. '''
  6. title = models.CharField(max_length=32, verbose_name='权限名称')
  7. url = models.CharField(max_length=200, verbose_name='url')
  8. def __str__(self):
  9. return self.title
  10. class Meta:
  11. verbose_name = '权限'
  12. verbose_name_plural = verbose_name
  13. class Role(models.Model):
  14. '''
  15. 角色类包括title:角色名称 permission:角色的权限
  16. 权限和角色多对多关系
  17. 用户类需要对Role类设置多对多映射
  18. '''
  19. title = models.CharField(max_length=32, verbose_name='角色名称')
  20. permission = models.ManyToManyField(Permission, verbose_name='权限')
  21. def __str__(self):
  22. return self.title
  23. class Meta:
  24. verbose_name = '角色'
  25. verbose_name_plural = verbose_name
  26. class Whitelist(models.Model):
  27. '''
  28. 白名单包括title:权限名称 url:权限具体url
  29. 白名单内存放的是系统放行不进行权限校验的url
  30. '''
  31. title = models.CharField(max_length=32, verbose_name='权限名称')
  32. url = models.CharField(max_length=200, verbose_name='url')
  33. def __str__(self):
  34. return self.title
  35. class Meta:
  36. verbose_name = '白名单'
  37. verbose_name_plural = verbose_name
  38. class NeedLogin(models.Model):
  39. '''
  40. 登录验证包括title:url标题 url:具体url
  41. 登录验证表存放的是需要登录才能进行操作或权限校验的url,如果没有登录则会重定向到登录页面
  42. '''
  43. title = models.CharField(max_length=32, verbose_name='url标题')
  44. url = models.CharField(max_length=200, verbose_name='url')
  45. def __str__(self):
  46. return self.title
  47. class Meta:
  48. verbose_name = '登录验证表'
  49. verbose_name_plural = verbose_name

中间件类介绍

VerifyPermissions

权限认证中间件实现了process_request和process_view方法。中间件在初始化时会从数据库更新白名单列表和需要登录认证的url列表,这个中间件实现了用户访问权限认证,登录认证功能。

verify.py

  1. from django.shortcuts import render, HttpResponse, redirect
  2. from permission.models import Whitelist, NeedLogin
  3. from django.utils.deprecation import MiddlewareMixin
  4. import re
  5. from django.conf import settings
  6. class VerifyPermissions(MiddlewareMixin):
  7. # 只在中间件加载时执行一次
  8. # 获取白名单列表
  9. whitelist = Whitelist.objects.values('url').all()
  10. # 获取需要登录的url列表
  11. needLogin_list = NeedLogin.objects.values('url').all()
  12. def process_request(self, request):
  13. '''
  14. 对用户的请求和登录验证的url进行匹配,如果匹配成功且用户没有登录,则重定向到登录页面
  15. 需要在settings.py配置LOGIN_URL
  16. :param request:
  17. :return:
  18. '''
  19. current_url = request.path
  20. # 从session中取用户登录的数据,在登录视图函数内,登录成功需要在session中存储登录用户信息,这里使用user作为登录用户信息的key
  21. user = request.session.get("user", "")
  22. # 校验是否是登录验证表的内容,如果是且已登录则放行,如果不是登录验证表的内容则会放行到urls.py,如果未登录则重定向到登录页面
  23. for url in self.needLogin_list:
  24. ret = re.fullmatch(url['url'], current_url)
  25. if ret:
  26. if user:
  27. return
  28. else:
  29. return redirect(settings.LOGIN_URL)
  30. def process_view(self, request, view_func, view_args, view_kwargs):
  31. '''
  32. 根据中间中process_*方法执行的顺序,process_view方法是在请求到达urls.py之后在执行view.py视图函数之前执行的
  33. 使用process_view方法不使用process_request是因为如果用户输入了找不到的路径,可以先提示404,不会先提示权限问题
  34. '''
  35. current_url = request.path
  36. # 校验是否是白名单的内容,如果是则放行
  37. for url in self.whitelist:
  38. ret = re.fullmatch(url['url'], current_url)
  39. if ret:
  40. return
  41. # 从session中获取权限列表
  42. permissions_list = request.session.get('permissions_list', [])
  43. # 校验是否是权限内的内容,如果不是提示权限不够
  44. for url in permissions_list:
  45. ret = re.fullmatch(url['url'], current_url)
  46. if ret:
  47. return
  48. else:
  49. # 可设置自定义页面
  50. return HttpResponse('权限不够')

管理员通过django的admin更新白名单或者登录验证表时需要及时更新中间件中的白名单列表和登录验证url列表,避免重启项目。这里使用重写admin.ModelAdmin的save_model和delete_model方法。

admin.py

  1. from django.contrib import admin
  2. from permission.models import *
  3. from permission.verify import VerifyPermissions
  4. class WhitelistAdmin(admin.ModelAdmin):
  5. '''
  6. 由于只在中间件加载第一次时加载白名单,所以对白名单内容做修改时,应对中间件中内容更新
  7. '''
  8. def save_model(self, request, obj, form, change):
  9. obj.save()
  10. VerifyPermissions.whitelist = Whitelist.objects.values('url').all()
  11. def delete_model(self, request, obj):
  12. obj.delete()
  13. VerifyPermissions.whitelist = Whitelist.objects.values('url').all()
  14. class NeedLoginAdmin(admin.ModelAdmin):
  15. '''
  16. 由于只在中间件加载第一次时加载登录验证表,所以对登录验证表内容做修改时,应对中间件中内容更新
  17. '''
  18. def save_model(self, request, obj, form, change):
  19. obj.save()
  20. VerifyPermissions.needLogin_list = NeedLogin.objects.values('url').all()
  21. def delete_model(self, request, obj):
  22. obj.delete()
  23. VerifyPermissions.needLogin_list = NeedLogin.objects.values('url').all()
  24. admin.site.register(Permission)
  25. admin.site.register(Role)
  26. admin.site.register(Whitelist, WhitelistAdmin)
  27. admin.site.register(NeedLogin, NeedLoginAdmin)

使用说明:

组件Github地址:https://github.com/WPN0837/RBAC

PS:Github上是组件的一个使用示例

只需要把permission下的内容复制到需要权限认证的项目中即可使用

在使用这个组件的项目中注册这个组件,在settings.py的INSTALLED_APPS添加'permission.apps.PermissionConfig',例如:

INSTALLED_APPS = [
    '''
    'permission.apps.PermissionConfig',
]

添加中间件,在settings.py的MIDDLEWARE添加'permission.verify.VerifyPermissions',例如:

MIDDLEWARE = [
    '''
    'permission.verify.VerifyPermissions',
]

PS:VerifyPermissions一定要写在SessionMiddleware后面,因为VerifyPermissions使用到了session

使用需要注意的地方:

在项目定义User类的地方需要先引入permission.models下的Role类

例如from permission.models import Role

再在User绑定User类与Role类多对多映射关系

具体如:

  1. class UserInfo(models.Model):
  2. username = models.CharField(max_length=20)
  3. pwd = models.CharField(max_length=20)
  4. # 绑定用户与角色多对多映射关系
  5. role = models.ManyToManyField(Role, verbose_name='角色')
  6. def __str__(self):
  7. return self.username

在配置文件settings.py文件中需要配置登录的URL,要与urls.py文件中相同,例如:

  1. # settings.py
  2. # 也可使用登录url的别名
  3. LOGIN_URL = "/login/"
  1. # urls.py
  2. urlpatterns = [
  3. path('admin/', admin.site.urls),
  4. path('', index),
  5. # 登录的url,也可以使用别名
  6. path('login/', login),
  7. ]

在用户登录视图函数里,如果登录成功应当把用户信息和用户权限信息保存到用户的session中,例如:

  1. def login(request):
  2. if request.method == 'GET':
  3. name = request.GET.get('name', '')
  4. pwd = request.GET.get('pwd', '')
  5. u = UserInfo.objects.filter(username=name, pwd=pwd).first()
  6. if u:
  7. # 保存用户信息
  8. request.session['user'] = name
  9. # 保存用户权限信息
  10. request.session['permissions_list'] = list(
  11. Permission.objects.filter(role__in=u.role.all()).values('url').all())
  12. return HttpResponse('登录成功')
  13. else:
  14. return HttpResponse('登录失败')

具体保存到session里的数据的key由中间件类VerifyPermissions的process_request(使用了user)和process_view(使用了permissions_list)方法里使用到session的地方决定,可自己修改。

在添加完组件后,首先迁移数据库文件,然后把中间件VerifyPermissions注释掉,再进入django admin管理后台,在白名单中添加/admin/.*这个url,权限名称可以设置成admin或者其他的,再取消中间件VerifyPermissions的注释,因为没有admin后台的url添加进白名单,会提示没有权限访问/admin/开头的url。

 

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

闽ICP备14008679号