zoukankan      html  css  js  c++  java
  • 【Python】django权限管理

    参考:http://www.cnblogs.com/esperyong/

    参考:https://docs.djangoproject.com/en/1.8/topics/auth/default/#topic-authorization

    在Django的世界中,在权限管理中有内置的Authentication系统。用来管理帐户,组,和许可。还有基于cookie的用户session。

    django中内置的权限控制1-User Model


    这篇blog主要用来探讨这套内置的Authentication系统。

    Django内置的权限系统包括以下三个部分:
    用户(Users)
    许可(Permissions):用来定义一个用户(user)是否能够做某项任务(task)
    组(Groups):一种可以批量分配许可到多个用户的通用方式

    首先需要在Django中安装这个组件:
    在settings.py配置好数据库连接,运行python manage.py syncdb 。这一步将生成管理界面使用的数据库表。
    将'django.contrib.auth'和'django.contrib.contenttypes'放到settings.py中的INSTALLED_APPS中(使用contenttypes的原因是auth中的Permission模型依赖于contenttypes)

    我们可以执行python manage.py shell来启动命令行,对其中的一些API进行学习和使用。

    >> User对象 <<

    首先最重要的开始就是User模型

    User模型对应于一个用户,一个帐户,位于'django.contrib.auth.models'模块中。
    User对象有两个多对多的属性分别是:groups和user_permissions

    >> 新建User对象 <<

    1 from django.contrib.auth.models import User
    2 u = User.objects.create_user('test1','test1','aaa')

    User对象的Manager,UserManager:
    和其他的模型一样,User模型类的objects属性也是一个Manager对象,但是User的Manager对象是自定义的,增加了一些方法:
    create_user(username,email=None,password=None)
    该方法创建保存一个is_active=True的User对象并返回。username不能够为空,否则抛出ValueError异常。email和password都是可选的。email的domain部分会被自动转变为小写。password如果没有提供,则User对象的set_unusable_password()方法将会被调用。
    make_random_password(length=10,allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')
    该方法返回一个给定长度和允许字符集的密码。其中默认的allowed_chars有一些字符没有,比如i,l等等。

    >> User对象的属性 <<:

      username:字符串类型。必填。30个字符以内。
      first_name:字符串类型。可选。30个字符以内。
      last_name:字符串类型。可选。30个字符以内。
      email:可选。
      password:明文密码的hash或者是某种元数据。该属性不应该直接赋值明文密码,而应该通过set_password()方法进行赋值,在后面有详细说明TODO。
      is_staff:Boolean类型。用这个来判断是否用户可以登录进入admin site。
      is_active:Boolean类型。用来判断该用户是否是可用激活状态。在删除一个帐户的时候,可以选择将这个属性置为False,而不是真正删除。这样如果应用有外键引用到这个用户,外键就不会被破坏。
      is_superuser:Boolean类型。该属性用来表示该用户拥有所有的许可,而无需明确的赋予给他。
      last_login:datetime类型。最近一次登陆时间。
      date_joined:datetime类型。创建时间。

    可以在新建用户时直接使用这些属性:

    1 from django.contrib.auth.models import User
    2 u = User.objects.create_user('test1','test1','aaa')
    3 u.first_name='a'
    4 u.first_name='b'
    5 u.save()

    >> 修改User对象 <<:

    1 from django.contrib.auth.models import User
    2 u = User.objects.get(username__exact='test1')
    3 u.username='test2'
    4 u.save()

    注意修改完对象属性需要u.save()。

    千万不要直接给User的password属性赋值,应该用set_password()方法进行赋值。

    Tips:这些用户属性就是将数据库中用户授权信息的赋值动作。

    用python manage.py changepassword *username*来进行修改,需要输入两次密码。

    >> User对象方法 << 

    像set_password()一样,除了DjangoModel对象的通用方法之外,User对象有以下特有方法:
      is_anonymous():
        永远返回False.用来将User对象和AnonymousUser(未登录的匿名用户)对象作区分用的识别方法。通常,最好用is_authenticated()方法。
      is_authenticated():
        永远返回True。该方法不代表该用户有任何的许可,也不代表该用户是active的,而只是表明该用户提供了正确的username和password。
      get_full_name():
        返回一个字符串,是first_name和last_name中间加一个空格组成。
      set_password(raw_password):
        调用该方法时候传入一个明文密码,该方法会进行hash转换。该方法调用之后并不会保存User对象。
      check_password(raw_password):
        如果传入的明文密码是正确的返回True。该方法和set_password是一对,也会考虑hash转换。
      set_unusable_password():
        将用户设置为没有密码的状态。调用该方法后,check_password()方法将会永远返回false。但是如果,调用set_password()方法重新设置密码后,该方法将会失效,has_usable_password()也会返回True。
      has_usable_password():
        在调用set_unusable_password()方法之后,该方法返回False,正常情况下返回True。
      get_group_permissions(obj=None):
        返回该用户通过组所拥有的许可(字符串列表每一个代表一个许可)。obj如果指定,将会返回关于该对象的许可,而不是模型。
      get_all_permissions(obj=None):
        返回该用户所拥有的所有的许可,包括通过组的和通过用户赋予的许可。
      has_perm(perm,obj=None):
        如果用户有传入的perm,则返回True。perm可以是一个格式为:'<app label>.<permission codename>'的字符串。如果User对象为inactive,该方法永远返回False。和前面一样,如果传入obj,则判断该用户对于这个对象是否有这个许可。
      has_perms(perm_list,obj=None):
        和has_perm一样,不同的地方是第一个参数是一个perm列表,只有用户拥有传入的每一个perm,返回值才是True。
      has_module_perms(package_name):
        传入的是Django app label,按照'<app label>.<permission codename>'格式。当用户拥有该app label下面所有的perm时,返回值为True。如果用户为inactive,返回值永远为False。
      email_user(subject,message,from_email=None):
        发送一封邮件给这个用户,依靠的当然是该用户的email属性。如果from_email不提供的话,Django会使用settings中的DEFAULT_FROM_EMAIL发送。
      get_profile():
        返回一个和Site相关的profile对象,用来存储额外的用户信息。这个返回值会在另一片博文中详细描述。

    django中内置的权限控制2-Login Logout


    而在Web应用中,任何的权限系统要做的第一步就是用户识别,也就是我们常说的登陆(login)。只有正确的登陆校验,知道用户是谁了,才能够知道用户能干什么,那就是许可(Permission)需要负责解决的事情,而Group则是批量设置许可的时候的一个便利手段。

    >> 请求用户是否登陆的验证 <<

    django有一套方法,可以在每个view方法能够接收到的request对象中增加权限验证相关的方法。要做到这一点,首先需要:

    在settings文件中对MIDDLEWARE_CLASSES变量增加上述两个Middleware类SessionMiddleware和AuthenticationMiddleware。

    1 MIDDLEWARE_CLASSES = (
    2     'django.contrib.sessions.middleware.SessionMiddleware',
    3     'django.middleware.locale.LocaleMiddleware',
    4     'django.middleware.common.CommonMiddleware',
    5     'django.middleware.csrf.CsrfViewMiddleware',
    6     'django.contrib.auth.middleware.AuthenticationMiddleware',
    7     'django.contrib.messages.middleware.MessageMiddleware',
    8     'django.middleware.transaction.TransactionMiddleware',
    9 )

    在view中,我们就可以使用request.user获取当前的登陆用户User对象。如果当前用户没有登陆,那么request.user将会是我们之前所说的AnonymousUser对象。我们可以用User对象的is_authenticated()方法将这两者区分开来,我们可以使用django新建一个项目,在view中进行测试:

    1 def test(request):
    2     if request.user.is_authenticated():
    3         return render_to_response('test.html',{'User_status':'login'})
    4     else:
    5         return render_to_response('test.html',{'User_status':'no login'})

    在相应的视图函数前面增加@login_required修饰符可以实现非登录用户禁止访问:

    from django.contrib.auth.decorators import login_required
    
    @login_required
    def test(request):
        ...

    1、如果用户没登录, 重定向到/accounts/login/(settings.LOGIN_URL),并且把当前绝对URL作为next参数用get方法传递过去

    2、如果用户已登录, 正常地执行视图函数

    >>authenticate验证<<

    使用命令行可以进行测试,authenticate(username,password)函数需要两个参数username,password,如果校验通过则返回User对象,如果校验不通过返回None,例如:

    from django.contrib.auth import authenticate, login
     
    def my_view(request):
        user = authenticate(username='root', password='admin')
        if user is not None:
            print "User ok"
        else:
            print "password err or no user"

    >> login_required <<

    定义:django.contrib.auth.decorators.login_required([redirect_field_name=REDIRECT_FIELD_NAME,login_url=None])

    login_required方法接受两个参数:
    redirect_field_name:默认值是next。用来定义登陆成功之后的跳回之前访问界面的url。
    login_url:默认值是settings.LOGIN_URL。用来指定登陆界面的url。如果不传入改参数,就需要确保settings.LOGIN_URL的值是正确设置的。

    1 from django.contrib.auth.decorators import login_required
    2  
    3 @login_required(login_url='/admin/')
    4 def test(request):
    5     ...

    示例view:

    from django.http import HttpResponse,HttpResponseRedirect
    from django.shortcuts import render_to_response
    from django.contrib.auth import authenticate, login, logout
    from django.contrib.auth.decorators import *
    
    def webpage_login(request):
        """ 
            页面 -> 登录
        """
        if request.GET.get('next') == None:
            next_path = '/index/'
        else:
            next_path = request.GET.get('next')
        page = {'next': request.path + '?next=' + next_path}
        if request.POST.get('user') and request.POST.get('password'):
            user_str, passwd_str = request.POST.get('user'), request.POST.get('password')
            if authenticate(username = user_str, password = passwd_str):
                user_object = authenticate(username = user_str, password = passwd_str)
                login(request, user_object)
                return HttpResponseRedirect(request.GET.get('next'))
            else:
                return HttpResponse("没有用户或密码错误")
        else:
            return render_to_response('login.html', page)

    示例template:

    <body class="login-bg">
            <div class="login-body">
                <div class="login-heading">
                    <h1>Login</h1>
                </div>
                <div class="login-info">
                    <form action="{{ next }}" method="post">
                        <input type="text" class="user" name="user" placeholder="User" required="">
                        <input type="password" name="password" class="lock" placeholder="Password">
                        <input type="submit" name="Sign In" value="Login">
                    </form>
                </div>
            </div>
    </body>

    django中内置的权限控制3-许可(Permission) 和 用户组(Group)


    >> 许可(Permissions)<<

    当我们在django中安装好了auth应用之后,Django就会为每一个你安装的app中的Model创建三个权限:add/change/delete,执行python manage.py syncdb之后相应的数据会插入到数据库中的。每一次你执行syncdb,Django都会为每个用户给新出现的Model增加这三个权限。

    例如,你创建了一个应用叫做school,里面有一个模型叫做StudyGroup,那么你可以用任何一个user对象执行下面的程序,其结果都返回True:

    1 user.hash_perm('school.add_studygroup')
    2 user.hash_perm('school.change_studygroup')
    3 user.hash_perm('school.delete_studygroup')

    我们也可以自己定义一些许可,就是在Model类的meta属性中添加permissions定义。比方说,创建了一个模型类叫做Discussion,我们可以创建几个权限来对这个模型的权限许可进行控制,控制某些人可以发起讨论、发起回复,关闭讨论:

    1 class Discussion(models.Model):
    2     ...
    3     class Meta:
    4         permissions = (
    5             ("open_discussion", "Can create a discussion"),
    6             ("reply_discussion", "Can reply discussion"),
    7             ("close_discussion", "Can remove a discussion by setting its status as closed"),
    8         )

    执行manage.py syncdb就会把增加的权限信息录入到后台数据库。

    通过某一个user的user_permissions属性,permission_1为auth_permission表中的id值:

    1 user.user_permissions.add(permission_1, permission_2, ...)

    删除权限:

    1 user.user_permissions.remove(permission_1, permission_2, ...)

    通过user的一个组,然后通过group的permissions属性:

    1 group.permissions.add(permission_1, permission_2, ...)

    我们要判断一个用户是否有发讨论的权限,我们可以用下面的代码:

    1 user.has_perm('school.open_discussion')

    Permission类和User类没什么特殊的,都是普通的DjangoModel。在第一篇文章中我们详细探讨了User模型的属性和方法。在这里我们探讨一下Permission模型和如何用编程的方式而不是通过预定义然后syncdb的方式创建permission。因为也许在某些时候,需要动态创建并分配权限。

    也可以通过Permission.objects.create()方法添加对应app中models的权限,如下app为svn中的模型定义Project添加除默认三个权限外的权限:

    1 from svn.models import Project
    2 from django.contrib.auth.models import Group, Permission
    3 from django.contrib.contenttypes.models import ContentType
    4 
    5 content_type = ContentType.objects.get_for_model(Project)
    6 permission = Permission.objects.create(codename='project_admin',
    7                                        name='Department administrator',
    8                                        content_type=content_type)
  • 相关阅读:
    【Uvalive4960】 Sensor network (苗条树,进化版)
    【UVA 1151】 Buy or Build (有某些特别的东东的最小生成树)
    【UVA 1395】 Slim Span (苗条树)
    【UVA 10600】 ACM Contest and Blackout(最小生成树和次小生成树)
    【UVA 10369】 Arctic Network (最小生成树)
    【UVA 10816】 Travel in Desert (最小瓶颈树+最短路)
    【UVA 11183】 Teen Girl Squad (定根MDST)
    【UVA 11865】 Stream My Contest (二分+MDST最小树形图)
    【UVA 11354】 Bond (最小瓶颈生成树、树上倍增)
    【LA 5713 】 Qin Shi Huang's National Road System (MST)
  • 原文地址:https://www.cnblogs.com/jiangxu67/p/4988304.html
Copyright © 2011-2022 走看看