Django的标准库存放在 django.contrib 包中。每个子包都是一个独立的附加功能包。

这些子包一般是互相独立的,不过有些django.contrib子包需要依赖其他子包,其中django.contrib.auth 为Django的用户验证框架

Django内置了用户认证系统,处理用户账号,用户组,权限,基于cookie的session,并且内置了一些快捷函数

官方网址  https://docs.djangoproject.com/en/1.11/topics/auth/

auth本质内置app,需要条件,Django默认已配置

INSTALLED_APPS
'django.contrib.auth'
'django.contrib.contenttypes'
MIDDLEWARE
'django.contrib.sessions.middleware.SessionMiddleware'
'django.contrib.auth.middleware.AuthenticationMiddleware'
User objects

核心,必须了解,为以后定制做准备

fields

  • username

  • password

  • email

  • first_name

  • last_name

  • groups

  • user_permissions

  • is_staff

  • is_active

  • is_superuser

  • last_login     # 最后登录时间

  • date_joined  # 账号添加时间

attr 

  • is_authenticated

  • is_anonymous

  • username_validator  # 用户名校验

method

  • get_username()

  • get_full_name()

  • get_short_name()

  • set_password()       # 加密处理,保持算法一致

  • check_password()  # 验证密码,和set_password() 算法一致

  • set_unusable_password()

  • has_unusable_password()

  • get_group_permissions()

  • get_all_permissions()

  • has_perm()

  • has_module_perms()

  • email_user()

源码分析

class User(AbstractUser):
# username, password and email 是必填项. 其他字段是可选的. class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'

User

class AbstractUser(AbstractBaseUser, PermissionsMixin):
"""
1. 抽象基类 不会生成库表,包含User的全部功能,并且具备权限
2. Username and password 必填项, 其他字段 可选项
"""
# 定义验证器
username_validator = UnicodeUsernameValidator() if six.PY3 else ASCIIUsernameValidator() # 用户名
username = models.CharField(
_('username'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
validators=[username_validator],
error_messages={
'unique': _("A user with that username already exists."),
},
) first_name = models.CharField(_('first name'), max_length=30, blank=True) # 英文类 名字
last_name = models.CharField(_('last name'), max_length=30, blank=True) # 英文类 姓
email = models.EmailField(_('email address'), blank=True) # 邮箱 # 是否可登陆admin后台
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this admin site.'),
)
# 是否激活,代替删除
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. '
'Unselect this instead of deleting accounts.'
),
)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now) # 创建时间 objects = UserManager() # 管理器为UserManger,继承BaseUserManager,继承models.Manager EMAIL_FIELD = 'email'
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email'] class Meta:
verbose_name = _('user') # model 名称
verbose_name_plural = _('users') # model 名称复数
abstract = True # 抽象基类,不会生成库表 # 所有字段验证后,最后的验证方法,只做了邮箱格式
def clean(self):
super(AbstractUser, self).clean()
self.email = self.__class__.objects.normalize_email(self.email) def get_full_name(self):
"""
Returns the first_name plus the last_name, with a space in between.
"""
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip() def get_short_name(self):
"Returns the short name for the user."
return self.first_name def email_user(self, subject, message, from_email=None, **kwargs):
# 发送email到该用户
send_mail(subject, message, from_email, [self.email], **kwargs)

AbstractUser

class AbstractBaseUser(models.Model):
password = models.CharField(_('password'), max_length=128) # 密码
last_login = models.DateTimeField(_('last login'), blank=True, null=True) # 最后登录时间 is_active = True # 用户默认激活 REQUIRED_FIELDS = [] class Meta:
abstract = True # 抽象基类 def get_username(self):
"""
1. 返回验证User标识的字段
2. 反射User的属性USERNAME_FIELD,这样的话,USERNAME_FIELD是可更改的
3. 父类如何访问子类的可变属性
"""
return getattr(self, self.USERNAME_FIELD) def __init__(self, *args, **kwargs):
super(AbstractBaseUser, self).__init__(*args, **kwargs)
# set_password()调用时,存储原始的密码,这样当model调用save()时,就直接可以保持了
self._password = None def __str__(self):
return self.get_username() # USERNAME_FIELD字段格式,clean()方法
def clean(self):
setattr(self, self.USERNAME_FIELD, self.normalize_username(self.get_username())) def save(self, *args, **kwargs):
super(AbstractBaseUser, self).save(*args, **kwargs)
if self._password is not None:
password_validation.password_changed(self._password, self)
self._password = None def natural_key(self):
return (self.get_username(),) @property
def is_anonymous(self):
# 总是返回 False,兼容anonymous user
return CallableFalse @property
def is_authenticated(self):
# 总是返回 True,Template一种验证是否登录的判断字段
return CallableTrue # 设置密码
def set_password(self, raw_password):
self.password = make_password(raw_password)
self._password = raw_password # 没看懂,大致了解整个密码需要加盐验证
def check_password(self, raw_password):
"""
Return a boolean of whether the raw_password was correct. Handles
hashing formats behind the scenes.
"""
def setter(raw_password):
self.set_password(raw_password)
# Password hash upgrades shouldn't be considered password changes.
self._password = None
self.save(update_fields=["password"])
return check_password(raw_password, self.password, setter) def set_unusable_password(self):
# Set a value that will never be a valid hash
self.password = make_password(None) def has_usable_password(self):
return is_password_usable(self.password) # 子类必须实现该方法,否则抛出异常
def get_full_name(self):
raise NotImplementedError('subclasses of AbstractBaseUser must provide a get_full_name() method') # 子类必须实现该方法,否则抛出异常
def get_short_name(self):
raise NotImplementedError('subclasses of AbstractBaseUser must provide a get_short_name() method.') def get_session_auth_hash(self):
"""
Return an HMAC of the password field.
"""
key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
return salted_hmac(key_salt, self.password).hexdigest() @classmethod
def get_email_field_name(cls):
# 返回表示邮箱的字段名
try:
return cls.EMAIL_FIELD
except AttributeError:
return 'email' @classmethod
def normalize_username(cls, username):
# 格式化 username
return unicodedata.normalize('NFKC', force_text(username))

AbstractBaseUser

class UserManager(BaseUserManager):
use_in_migrations = True def _create_user(self, username, email, password, **extra_fields):
# 内部方法,给定的username,email和password创建用户
# 把功能部分提取出来,供普通用户和管理员用户创建使用
if not username:
raise ValueError('The given username must be set')
email = self.normalize_email(email)
username = self.model.normalize_username(username)
user = self.model(username=username, email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user # 创建普通用户
def create_user(self, username, email=None, password=None, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(username, email, password, **extra_fields) # 创建管理员用户
def create_superuser(self, username, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True) if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.') return self._create_user(username, email, password, **extra_fields)

UserManager

class PermissionsMixin(models.Model):

    # 是否是超级管理员
is_superuser = models.BooleanField(
_('superuser status'),
default=False,
help_text=_(
'Designates that this user has all permissions without '
'explicitly assigning them.'
),
)
# 一个用户可以属于多个组,一个组可包含多个用户
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",
) class Meta:
abstract = True def get_group_permissions(self, obj=None):
"""
Returns a list of permission strings that this user has through their
groups. This method queries all available auth backends. If an object
is passed in, only permissions matching this object are returned.
"""
permissions = set()
for backend in auth.get_backends():
if hasattr(backend, "get_group_permissions"):
permissions.update(backend.get_group_permissions(self, obj))
return permissions def get_all_permissions(self, obj=None):
return _user_get_all_permissions(self, obj) 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) def has_perms(self, perm_list, obj=None):
"""
Returns True if the user has each of the specified permissions. If
object is passed, it checks if the user has all required perms for this
object.
"""
return all(self.has_perm(perm, obj) for perm in perm_list) def has_module_perms(self, app_label):
"""
Returns True if the user has any permissions in the given app label.
Uses pretty much the same logic as has_perm, above.
"""
# Active superusers have all permissions.
if self.is_active and self.is_superuser:
return True return _user_has_module_perms(self, app_label)

PermissionsMixin

说明:

  • AbstractUser,抽象基类,包含username基本信息,但是没有密码信息,继承AbstractBaseUser和PermissionsMixin

  • AbstractBaseUser,抽象基类,实现password相关信息

  • PermissionsMixin,抽象基类,实现权限相关信息

  • 管理器UserManager,实现user的

  • User继承抽象基类AbstractUser,AbstractUser的管理器objects=UserManager()

AnonmousUser

匿名用户,实现User常见方法,调用User方法不会报错,一种权限模型,但是和User有区别

  • id 为None

  • username 空字符串

  • get_username() 空字符串

  • is_anonymous 为True

  • is_authenticated 为True

  • is_staff 为False

  • is_superuser 为False

  • is_active 为False

  • groups 和 user_permissions 为空

  • set_password(), check_password(), save(), delete() 抛NotImplementedError

class AnonymousUser(object):
id = None
pk = None
username = ''
is_staff = False
is_active = False
is_superuser = False
_groups = EmptyManager(Group)
_user_permissions = EmptyManager(Permission) def __init__(self):
pass def __str__(self):
return 'AnonymousUser' def __eq__(self, other):
return isinstance(other, self.__class__) def __ne__(self, other):
return not self.__eq__(other) def __hash__(self):
return 1 # instances always return the same hash value def save(self):
raise NotImplementedError("Django doesn't provide a DB representation for AnonymousUser.") def delete(self):
raise NotImplementedError("Django doesn't provide a DB representation for AnonymousUser.") def set_password(self, raw_password):
raise NotImplementedError("Django doesn't provide a DB representation for AnonymousUser.") def check_password(self, raw_password):
raise NotImplementedError("Django doesn't provide a DB representation for AnonymousUser.") @property
def groups(self):
return self._groups @property
def user_permissions(self):
return self._user_permissions def get_group_permissions(self, obj=None):
return set() def get_all_permissions(self, obj=None):
return _user_get_all_permissions(self, obj=obj) def has_perm(self, perm, obj=None):
return _user_has_perm(self, perm, obj=obj) def has_perms(self, perm_list, obj=None):
for perm in perm_list:
if not self.has_perm(perm, obj):
return False
return True def has_module_perms(self, module):
return _user_has_module_perms(self, module) @property
def is_anonymous(self):
return CallableTrue @property
def is_authenticated(self):
return CallableFalse def get_username(self):
return self.username

创建用户

另一种方式$  python manage.py createsuperuser --username=jonathan --email=jonathan@email.com

更改密码

另一种方式$ python manage.py  changepassword jonathan

注意:哪些是管理器的方法(如create_user),哪些是实例的方法(如set_password)

认证,登录和登出

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate, login, logout @login_required
def dashboard(request):
return render(request, 'dashboard.html') def account_login(request):
if request.method == "POST":
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(username=username, password=password)
if user:
login(request, user)
return redirect(request.GET.get('next') or '/dashboard/')
return render(request, 'login.html') def account_logout(request):
logout(request)
return redirect('/login/')
  • @login_required 验证需要登录的页面,否则跳转找配置里的登录页面 LOGIN_URL = '/login/'

  • next 后面跟的是登录成功后跳转的url
  • authenticate(username=username, password=password),认证通过返回user对象,否则None

  • login(request, user)  把user写入request

  • logout(request)  request中user

Cookie and session

http协议没有状态,cookie让http请求的时候携带状态,cookie保存在浏览器缓存中,和域名有关系,

以key:value 键值对实现页面间的数据共享,安全性低

cookie based sessions:session是基于cookie来做的,只不过保存了一个sessionid,所有其它内容都在服务端存储,

用来鉴别用户是否登录,以及其他信息,session要比cookie安全

和库表 django_session保存的session_key是一致的,并且session_data是加密的,有过期时间

cookie和session相关函数,属性,model

  • request.set_cookie

  • request.cookie['key']

  • request.session['key']

  • django.contrib.sessions.models.Session

自定义 user model

from django.db import models
from django.contrib.auth.models import AbstractUser class User(AbstractUser):
USER_ROLE_CHOICES = (
('SU', 'SuperUser'),
('GA', 'GroupAdmin'),
('CU', 'CommonUser'),
)
name = models.CharField(max_length=80)
uuid = models.CharField(max_length=100)
role = models.CharField(max_length=2, choices=USER_ROLE_CHOICES, default='CU')
ssh_key_pwd = models.CharField(max_length=200) def __str__(self):
return self.name # settings.py
AUTH_USER_MODEL = 'userapp.User'

说明:

1.  AbstractUser是抽象基类,不会生成库表

2. 告诉Django系统,认证 AUTH_USER_MODEL = 'userapp.User'

授权

Django权限系统实现了全局的授权机制,没有提供对象级别的授权,不过Django留有接口用来扩展

全局的授权的机制可以描述为:是否有某张表的权限(增加,编辑,删除)

对象基本的授权机制可以描述为:是否拥有表中某个对象的权限(增加,编辑,删除)

权限模型

Permission Model

Fields:

  • name('Can vote')

  • content_type(ForeignKey djano_content_type)

  • codename('can_vote')

ContentType Model

Fields:

  • app_label

  • model

Group Model

name

permissions(ManyToManyFiled Perm

表 auto_permission

表django_content_type

简单使用

用户权限

说明:has_perm('app_label.codename')

用户组权限

说明:用户会继承用户组的权限

Group model

view使用

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url='/login/')
def my_view(request):
pass

Django Auth 专题的更多相关文章

  1. Django auth 登陆后页面跳转至/account/profile,修改跳转至其他页面

    这几天在学习django,django功能很强大,自带的auth,基本可以满足用户注册登陆登出,简单的用户注册登陆系统使用django auth足矣.当然也不是拿来就能用的,需要自己写登陆页面的模板, ...

  2. Django auth认证

    Django自带的用户认证 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能,这还真是个麻烦的事情呢. Djang ...

  3. django auth permission

    django 提供内置view处理登陆和退出. 查看django.contrib.auth源码,主要查看三个函数authenticate,login,logout. authenticate(requ ...

  4. Django auth认证系统

    Django自带的用户认证 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能,这还真是个麻烦的事情呢. Djang ...

  5. django ---Auth模块

    Auth模块 本文目录 1 Auth模块是什么 2 auth模块常用方法 3 扩展默认的auth_user表 回到目录 1 Auth模块是什么 Auth模块是Django自带的用户认证模块: 我们在开 ...

  6. 【Python】Django auth 修改密码如何实现?

    使用示例1.创建用户>>> from django.contrib.auth.models import User>>> user = User.objects.c ...

  7. Django——auth用户认证

    之前我们在进行用户校验的时候,总是从数据库中获取数据,然后再进行对比,就像如下这样: def login(request): if request.method == "POST" ...

  8. Django auth权限

    创建超级管理员命令 python manage.py createsuperuser --username hello 检查和校验用户 from django.contrib import auth ...

  9. [Django] Auth django app with rest api

    First, start the env: . bin/activate Then cd to our module cd djangular Create a new app: python man ...

随机推荐

  1. Android 开发 知晓各种id信息 获取线程ID、activityID、内核ID

    /** * Returns the identifier of this process's user. * 返回此进程的用户的标识符. */ Log.e(TAG, "Process.myU ...

  2. Mysql TIMESTAMPDIFF测试

    select TIMESTAMPDIFF(DAY, '2015-04-20 00:00:00', '2015-04-20 23:59:59');# 只要不足24小时 为0天 select TIMEST ...

  3. spring boot 错误处理之深度历险

    今天终于把 boot 的异常处理完全研究透了: boot提供了很多错误的处理工作.默认情况下,我们会看到一个whiteLabel(白标)的页面. 这个可能不是我们所需.因此我们需要定制.我于是做了个深 ...

  4. PHP安装Commposer

    一先把php加到环境变量里面测试 看一下版本号: 二,composer得安装注意安装的时候 php必须在5.59以上版本,openssl的扩展开启,pdo的扩展开启,mbstring的扩展开启 1,下 ...

  5. threading.local()源码分析

    前段时间写了个多线程的程序,了解到Python中有个与众不同的thread.local()方法,可以创建一个全局对象,各个线程可以用这个全局对象保存各自的局部变量,而在使用时不受其他线程的影响.于是抽 ...

  6. 使用swiper插件,隐藏swiper后再显示,不会触发自动播放的解决办法

    问题: 项目中有一个需求,当点击P1时,两个页面进行轮播.当点击P2时,页面不轮播. 设置好以后,点击P2,再点击P1,此时页面不能自动轮播,只能手动触发. 解决: 在轮播器配置里,配置observe ...

  7. JMM中的重排序及内存屏障

    目录 1. 概述 2. 重排序 2-1. as-if-serial语义 2-2. 重排序的种类 2-3. 从Java源代码到最终实际执行的指令序列, 会分别经历下面3中重排序. 3. 内存屏障类型 3 ...

  8. 如何关闭wps热点,如何关闭wpscenter,如何关闭我的wps

    用wps已经快十年了,最开始的时候速度快,非常好用,甩office几条街,但最近这几年随着wps胃口越来越大,各种在线功能不断推出,植入广告越来越多,逐渐让人失去欢喜. 通过各种网帖的经验,我把网上流 ...

  9. ubuntu安装jdk,maven,tomcat

    ubuntu16.04安装jdk8 -jdk 检查是否安装成功 java -version 出现如上信息即安装成功 安装maven,先去官网下载指定版本的maven,个人使用apache-maven- ...

  10. 正确理解c和c ++的复杂类型声明

    本文作者girlrong是网易广州社区的C语言版版主,这篇文章被选在精华区.很是不错,不敢独享!据说她乐于助人,虚心诚恳,颇受网友欢迎.只可惜现在已退隐江湖了.在最近学习C语言过程中,了解些前辈大牛的 ...