浅谈 Django内部 用户认证 模块
我们之前学习了Django 的cookies和session的方法用于用户认证,其实Django框架内部已经内部封装一个用于用户认证的方法!今天有时间研究了下,瞬间感觉Django真是细微之至!
转自:原文出处
auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组和权限管理。
auth可以和admin模块配合使用, 快速建立网站的管理系统。
在Django框架同名的settings.py配置文件中,可以在INSTALLED_APPS的配置信息中看到'django.contrib.auth'用于使用该APP, auth模块默认启用。
User
User是auth模块中维护用户信息的关系模式(继承了models.Model), 数据库中该表被命名为auth_user.
User对象是认证系统的核心。用户对象通常用来代表网站的用户,并支持例如访问控制、注册用户、关联创建者和内容等。在Django认证框架中只有一个用户类,例如超级用户('superusers’)或('staff')用户只不过是相同用户对象设置了不同属性而已。
User表的SQL描述:
CREATE TABLE "auth_user" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "password" varchar(128) NOT NULL, "last_login" datetime NULL, "is_superuser" bool NOT NULL, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL, "email" varchar(254) NOT NULL, "is_staff" bool NOT NULL, "is_active" bool NOT NULL, "date_joined" datetime NOT NULL, "username" varchar(30) NOT NULL UNIQUE )
User表内各字段解释
username 用户名,必需字段。30个字符或更少,可以包含 _, @, +, . 和 - 字符。 first_name 可选。 30 characters or fewer. last_name 可选。 30 characters or fewer. email 邮箱,可选。 Email address. password 密码,必需。Django不是以明文存储密码的,而是存储哈希值。 groups 用户组。Many-to-many relationship to Group user_permissions 用户权限。Many-to-many relationship to Permission groups = models.ManyToManyField(Group, verbose_name=_('groups'), blank=True, help_text=_('The groups this user belongs to. A user will ' 'get all permissions granted to each of ' 'their groups.'), related_name="user_set", related_query_name="user") user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True, help_text=_('Specific permissions for this user.'), related_name="user_set", related_query_name="user") is_staff Boolean。决定用户是否可以访问admin管理界面。默认False。 is_active Boolean。 用户是否活跃,默认True。一般不删除用户,而是将用户的is_active设为False。 is_superuser Boolean。默认False。当设为True时,用户获得全部权限。 def has_perm(self, perm, obj=None): """ Returns True if the user has the specified permission. This method queries all available auth backends, but returns immediately if any backend returns True. Thus, a user who has permission from a single auth backend is assumed to have permission in general. If an object is provided, permissions for this specific object are checked. """ # Active superusers have all permissions. if self.is_active and self.is_superuser: return True # Otherwise we need to check the backends. return _user_has_perm(self, perm, obj) last_login 上一次的登录时间,为datetime对象,默认为当时的时间。 user.last_login = timezone.now() date_joined 用户创建的时间
User对象的使用方法Methods
is_anonymous() 是否是匿名用户。 is_authenticated()用户是否通过验证,登陆。 get_full_name() 返回first_name plus the last_name, with a space in between. get_short_name() 返回first_name. set_password(raw_password) 设置密码。 check_password(raw_password) 验证密码。 get_group_permissions(obj=None) 返回用户组权限的集合。 get_all_permissions(obj=None) 返回用户所有的权限集合。 has_perm(perm, obj=None) 用户是否具有某个权限。perm的格式是 "<app label>.<permission codename>". has_perms(perm_list, obj=None) 用户是否具有权限列表中的每个权限。
以上就是django自带的用户认证系统使用的模型的全部字段和方法,也就是说django在数据库中储存的字段信息就是以上这些。
auth模块提供了很多API管理用户信息, 在必要的时候我们可以APP的models.py文件中导入User表进行用户认证操作, 比如其它表需要与User建立关联时:
from django.contrib.auth.models import User
如果需要扩展的话,有两种方法:
1、另外再写一个模型,用OneToOne的形式关联到User中:
from django.db import models from django.contrib.auth.models import User class UserInfo(models.Model): user = models.OneToOneField(User) head_img = models.ImageField() # 其它扩展
2、另写一个模型,直接继承User:
from django.db import models from django.contrib.auth.models import User class UserInfo(User): head_img = models.ImageField() # 其它扩展
无论哪种方法都可以,因为那些已经定义好的字段都是储存在User表中的,而新增的字段储存在另外的表中,只是使用OneToOne的时候,查询的入口略麻烦了些,详情参考django的models。
创建用户
由于User对象的密码不是明文存储的而是存储一个Hash值, 比如迭代使用Md5算法,所以创建User对象时与通常的Model create不同,需用内置的create_user()方法。
user = User.objects.create_user(username, email, password) user.save() #建立user对象 在此,需要调用save()方法才可将此新用户保存到数据库中。
当然也可以在admin界面中添加用户。使用命令创建超级用户!
python manage.py createsuperuser
认证用户 authenticate()
验证给出的username和password是否是一个有效用户。如果有效,则返回一个User对象,无效则返回None。
使用authenticate模块,使用时,先导入模块:
from django.contrib.auth import authenticate
使用关键字参数传递账户和凭据:
user = authenticate(username=username, password=password) #认证用户的密码是否有效, 若有效则返回代表该用户的user对象, 若无效则返回None。
需要注意的是:该方法不检查is_active标志位。
修改用户密码
修改密码是User的实例方法, 该方法不验证用户身份:
user.set_password(new_password)
通常该方法需要和authenticate配合使用:
user = auth.authenticate(username=username, password=old_password) if user is not None: user.set_password(new_password) user.save()
登录
先导入模块:
from django.contrib.auth import login
login向session中添加SESSION_KEY, 便于对用户进行跟踪:
login(request, user)
login不进行认证,也不检查is_active标志位, 一般和authenticate配合使用:
user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user)
在auth/__init__.py中可以看到login的源代码。
退出登录
logout会移除request中的user信息, 并刷新session:
from django.contrib.auth import logout def logout_view(request): logout(request)
权限判断,只允许登录用户访问
@login_required修饰器修饰的view函数会先通过session key检查是否登录, 已登录用户可以正常的执行操作, 未登录用户将被重定向到login_url指定的位置。若未指定login_url参数, 则重定向到settings.LOGIN_URL。
from django.contrib.auth.decorators import login_required @login_required(login_url='/accounts/login/') def my_view(request): ...
Group
django.contrib.auth.models.Group定义了用户组的模型, 每个用户组拥有id和name两个字段, 该模型在数据库被映射为auth_group数据表。
User对象中有一个名为groups的多对多字段, 多对多关系由auth_user_groups数据表维护。Group对象可以通过user_set反向查询用户组中的用户。
我们可以通过创建删除Group对象来添加或删除用户组:
# add group = Group.objects.create(name=group_name) group.save() # del group.delete()
我们可以通过标准的多对多字段操作管理用户与用户组的关系:
#用户加入用户组 user.groups.add(group) #或者 group.user_set.add(user) #用户退出用户组 user.groups.remove(group) #或者 group.user_set.remove(user) #用户退出所有用户组 user.groups.clear() #用户组中所有用户退出组 group.user_set.clear()
Permission
Django的auth系统提供了模型级的权限控制, 即可以检查用户是否对某个数据表拥有增(add), 改(change), 删(delete)权限。
auth系统无法提供对象级的权限控制, 即检查用户是否对数据表中某条记录拥有增改删的权限。如果需要对象级权限控制可以使用django-guardian。
假设在博客系统中有一张article数据表管理博文, auth可以检查某个用户是否拥有对所有博文的管理权限, 但无法检查用户对某一篇博文是否拥有管理权限。
检查用户权限
user.has_perm方法用于检查用户是否拥有操作某个模型的权限:
user.has_perm('blog.add_article') user.has_perm('blog.change_article') user.has_perm('blog.delete_article')
上述语句检查用户是否拥有blog这个app中article模型的添加权限, 若拥有权限则返回True。
has_perm仅是进行权限检查, 即是用户没有权限它也不会阻止程序员执行相关操作。
@permission_required装饰器可以代替has_perm并在用户没有相应权限时重定向到登录页或者抛出异常。
# permission_required(perm[, login_url=None, raise_exception=False]) @permission_required('blog.add_article') def post_article(request): pass
每个模型默认拥有增(add), 改(change), 删(delete)权限。在django.contrib.auth.models.Permission模型中保存了项目中所有权限。
该模型在数据库中被保存为auth_permission数据表。每条权限拥有id ,name , content_type_id, codename四个字段。
管理用户权限
User和Permission通过多对多字段user.user_permissions关联,在数据库中由auth_user_user_permissions数据表维护。
#添加权限 user.user_permissions.add(permission) #删除权限: user.user_permissions.delete(permission) #清空权限: user.user_permissions.clear()
用户拥有他所在用户组的权限, 使用用户组管理权限是一个更方便的方法。Group中包含多对多字段permissions, 在数据库中由auth_group_permissions数据表维护。
#添加权限: group.permissions.add(permission) #删除权限: group.permissions.delete(permission) #清空权限: group.permissions.clear()
自定义权限
在定义Model时可以使用Meta自定义权限:
class Discussion(models.Model): ... class Meta: permissions = ( ("create_discussion", "Can create a discussion"), ("reply_discussion", "Can reply discussion"), )
判断用户是否拥有自定义权限:
user.has_perm('blog.create_discussion')