参考:http://www.cnblogs.com/esperyong/html
参考:https://docs.djangoproject.com/en/1.8/topics/auth/default/#topic-authorizationpython
在Django的世界中,在权限管理中有内置的Authentication系统。用来管理账户,组,和许可。还有基于cookie的用户session。web
django中内置的权限控制1-User Modelshell
这篇blog主要用来探讨这套内置的Authentication系统。数据库
Django内置的权限系统包括如下三个部分:
用户(Users)
许可(Permissions):用来定义一个用户(user)是否可以作某项任务(task)
组(Groups):一种能够批量分配许可到多个用户的通用方式django
首先须要在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进行学习和使用。cookie
>> User对象 <<session
首先最重要的开始就是User模型app
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): ...
一、若是用户没登陆, 重定向到/accounts/login/(settings.LOGIN_URL),而且把当前绝对URL做为next参数用get方法传递过去
二、若是用户已登陆, 正常地执行视图函数
>>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)