验证与授权
Django有一个内置的授权系统:包括验证和授权两个部分。用来处理用户、分组、权限以及基于cookie的会话系统。
验证:验证这个用户是否是他声称的人(比如用户名和密码验证,角色验证)
授权:给与他相应的权限。
Django内置的权限系统:
- 用户。
- 权限。
- 分组。
- 一个可以配置的密码哈希系统。
- 一个可插拔的后台管理系统。
授权系统:默认中创建完一个django项目后,就已经集成了授权系统。
INSTALLED_APPS:
- django.contrib.auth:包含了一个核心授权框架,以及大部分的模型定义。
- django.contrib.contenttypes:Content Type系统,可以用来关联模型和权限。
中间件:
SessionMiddleware:用来管理session。
AuthenticationMiddleware:用来处理和当前session相关联的用户。
User模型
该框架的核心部分。完整的路径 django.contrib.auth.models.User
内置的User模型拥有的字段:
- username: 用户名。150个字符以内。可以包含数字和英文字符,以及_、@、+、.和-字符。不能为空,且唯一!
- first_name:在30个字符以内。可为空。
- last_name:在150个字符以内。可为空。
- email:邮箱。可为空。
- password:密码。经过哈希过后的密码。
- groups:分组。一个用户可以属于多个分组,一个分组可以拥有多个用户。groups这个字段是跟Group的一种多对多的关系。
- user_permissions:权限。一个用户可以拥有多个权限,一个权限可以被多个用户所有用。和Permission属于一种多对多的关系。
- is_staff:是否可以进入到admin的站点。代表是否是员工。
- is_active:是否是可用的。对于一些想要删除账号的数据,我们设置这个值为False就可以了,而不是真正的从数据库中删除。
- is_superuser:是否是超级管理员。如果是,那么拥有整个网站的所有权限。
- last_login:上次登录的时间。
- date_joined:账号创建的时间。
基本用法:
- 创建用户:通过 create_user 方法创建用户。该方法必须要传递 username、email、password;
- 创建超级用户:
- 代码的方式。与创建普通用户类似,需使用 create_superuser ;
- 命令行的方式: python manage.py createsuperuser
1 from django.http import HttpResponse 2 from django.contrib.auth.models import User 3 4 def index(request): 5 # 创建普通用户 6 user = User.objects.create_user(username='jack',email='jack@123.com',password='111111') 7 # 创建超级用户 8 user = User.objects.create_superuser(username='Alen', email='Alen@123.com', password='111111') 9 return HttpResponse('success')
修改密码:
密码是需要经过加密后才能存储进去的。不能直接修改 password 字段,需要调用 set_password 来修改密码。
1 user = User.objects.get(pk=1) 2 user.set_password('填写新密码') 3 user.save()
登录验证:
Django的验证系统已经通过 django.contrib.auth.authenticate 实现了登录验证的功能。该方法只能通过 username 和 password 来进行验证。
1 from django.contrib.auth import authenticate 2 3 def index(request): 4 username = 'jack' 5 password = '111111' 6 user = authenticate(request,username=username,password=password) 7 if user: 8 print('登录成功:%s'% username) 9 else: 10 print('用户名或密码错误!') 11 return HttpResponse('success')
扩展用户模型:
在验证用户登录的时候,用的是用户名作为验证,而有时候需要通过手机号码或者邮箱来进行验证。或者需要增加一些新的字段。这时就需要扩展用户模型。
- 设置Proxy模型:对Django提供的字段,以及验证的方法没有需要改的,只需要在原有的基础之上增加一些操作的方法。使用这种方式。
1 from django.db import models 2 from django.contrib.auth.models import User 3 4 # 使用代理模型,不能添加新的Field;可加新属性; 5 class Person(User): 6 class Meta: 7 proxy = True 8 #增加黑名单属性; 9 @classmethod 10 def get_blacklsit(cls): 11 return cls.objects.filter(is_active=False)
1 from .models import Person 2 from django.contrib.auth.models import User 3 from django.http import HttpResponse 4 5 # 提取数据表单中“is_active=0”的黑名单数据;(‘auth_user’表单已存储数据) 6 def get_blacklist(request): 7 black_list = Person.get_blacklsit() 8 for person in black_list: 9 print(person.username) 10 return HttpResponse('proxy')
定义了一个 Person类 ,继承自 User ,Meta 中设置 proxy=True ,说明这只是 User 的一个代理模型。不影响原来User模型在数据库中表的结构。且 User.objects.all() 和 Person.objects.all() 是等价的。都是从User这个模型中获取所有的数据。
- 一对一外键:对用户验证方法 authenticate 不满足,需要在原来模型的基础上添加新的字段。
1 from django.db import models 2 from django.contrib.auth.models import User 3 from django.dispatch import receiver 4 from django.db.models.signals import post_save 5 6 # 使用一对一外键扩展 7 class UserExtension(models.Model): 8 user = models.OneToOneField(User,on_delete=models.CASCADE,related_name='extension') 9 telephone = models.CharField(max_length=11) 10 school = models.CharField(max_length=100) 11 12 # @receiver:用于将接收器连接到信号的装饰器。通过传入使用信号(或信号列表)和连接的关键字参数; 13 # sender:发送者 ; instance:调用save的实例 ; created:是否是新创建的; 14 # 接收User的save信号; 15 @receiver(post_save,sender=User) 16 def handler_user_extension(sender,instance,created,**kwargs): 17 if created: 18 UserExtension.objects.create(user=instance) 19 else: 20 instance.extension.save()
1 from django.shortcuts import render 2 from django.http import HttpResponse 3 from django.contrib.auth import authenticate 4 from .models import UserExtension 5 from django.contrib.auth.models import User 6 7 # 自定义验证号码及密码; 8 def my_authenticate(telephone,password): 9 user = User.objects.filter(extension__telephone=telephone).first() 10 if user: 11 is_correct = user.check_password(password) 12 if is_correct: 13 return user 14 else: 15 return None 16 else: 17 return None 18 19 def one_view(request): 20 # 创建用户,使用外键反向引用添加telephone; 21 # user = User.objects.create_user(username='three',password='111111',email='three@123.com') 22 # user.extension.telephone = '18988889999' 23 # user.save() 24 # 进行验证; 25 telephone = request.GET.get('telephone') 26 password = request.GET.get('password') 27 user = my_authenticate(telephone,password) 28 if user: 29 print('%s:验证成功'% user.username) 30 else: 31 print('用户验证失败!') 32 return HttpResponse('success')
定义一个 UserExtension的模型 与 User模型 进行一对一的绑定,以后新增的字段,就添加到 UserExtension 上。创建一个接受保存模型的信号处理方法,只要 User 调用了 save 方法,就会创建一个 UserExtension 和 User 进行绑定。
登录、注销和登录限制
登录用户:
1 from django.contrib.auth import login 2 3 def my_login(request): 4 if request.method == 'GET': 5 return render(request,'login.html') 6 else: 7 form = LoginForm(request.POST) 8 if form.is_valid(): 9 telephone = form.cleaned_data.get('telephone') 10 password = form.cleaned_data.get('password') 11 remember = form.cleaned_data.get('remember') 12 user = my_authenticate(telephone=telephone,password=password) 13 if user and user.is_active: 14 # 判断通过时登录成功,会生成session数据;再判断是否记住数据; 15 login(request,user) 16 if remember: 17 request.session.set_expiry(None) 18 else: 19 request.session.set_expiry(0) 20 # 定义获取next时的跳转页面 21 next_url = request.GET.get('next') 22 if next_url: 23 return redirect(next_url) 24 else: 25 return HttpResponse('登录成功') 26 else: 27 return HttpResponse('手机号或密码错误!') 28 else: 29 print(form.errors) 30 return redirect(reverse('login'))
1 <!--login.html--> 2 <tr> 3 <td> 4 <label for=""> 5 <input type="checkbox" name="remember" value="1">记住密码 6 </label> 7 </td> 8 </tr>
注销用户:
1 from django.contrib.auth import logout 2 3 # 注销用户 4 def my_logout(request): 5 logout(request) 6 return HttpResponse('退出登录')
登录限制:
1 from django.contrib.auth.decorators import login_required 2 3 # 登录限制,验证失败是会跳转到‘/login/’的url页面; 4 @login_required(login_url='/login/') 5 def profile(request): 6 return HttpResponse('个人中心,登录才能查看!')