Django自定义用户认证示例详解


Posted in Python onMarch 14, 2018

前言

Django附带的认证对于大多数常见情况来说已经足够了,但是如何在 Django 中使用自定义的数据表进行用户认证,有一种较为笨蛋的办法就是自定义好数据表后,使用OnetoOne来跟 Django 的表进行关联,类似于这样:

from django.contrib.auth.models import User
class UserProfile(models.Model):
 """
 用户账号表
 """
 user = models.OneToOneField(User)
 name = models.CharField(max_length=32)
 def __str__(self):
  return self.name
 class Meta:
  verbose_name_plural = verbose_name = "用户账号"
  ordering = ['id']

这样做虽然可以简单、快速的实现,但是有一个问题就是我们在自己的表中创建一个用户就必须再跟 admin 中的一个用户进行关联,这简直是不可以忍受的。

admin代替默认User model

写我们自定义的 models 类来创建用户数据表来代替默认的User model,而不与django admin的进行关联,相关的官方文档在这里

?戳我

from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import (
 BaseUserManager, AbstractBaseUser
)
class UserProfileManager(BaseUserManager):
 def create_user(self, email, name, password=None):
  """
  用户创建,需要提供 email、name、password
  """
  if not email:
   raise ValueError('Users must have an email address')
  user = self.model(
   email=self.normalize_email(email),
   name=name,
  )
  user.set_password(password)
  user.save(using=self._db)
  return user
 def create_superuser(self, email, name, password):
  """
  超级用户创建,需要提供 email、name、password
  """
  user = self.create_user(
   email,
   password=password,
   name=name,
  )
  user.is_admin = True
  user.is_active = True
  user.save(using=self._db)
  return user
class UserProfile(AbstractBaseUser):
 # 在此处可以配置更多的自定义字段
 email = models.EmailField(
  verbose_name='email address',
  max_length=255,
  unique=True,
 )
 name = models.CharField(max_length=32, verbose_name="用户名称")
 phone = models.IntegerField("电话")
 is_active = models.BooleanField(default=True)
 is_admin = models.BooleanField(default=False)
 objects = UserProfileManager()
 USERNAME_FIELD = 'email' # 将email 作为登入用户名
 REQUIRED_FIELDS = ['name', 'phone']
 def __str__(self):
  return self.email
 def get_full_name(self):
  # The user is identified by their email address
  return self.email
 def get_short_name(self):
  # The user is identified by their email address
  return self.email
 def has_perm(self, perm, obj=None):
  "Does the user have a specific permission?"
  # Simplest possible answer: Yes, always
  return True
 def has_module_perms(self, app_label):
  "Does the user have permissions to view the app `app_label`?"
  # Simplest possible answer: Yes, always
  return True
 @property
 def is_staff(self):
  "Is the user a member of staff?"
  # Simplest possible answer: All admins are staff
  return self.is_admin

admin 配置

class UserCreationForm(forms.ModelForm):
 """A form for creating new users. Includes all the required
 fields, plus a repeated password."""
 password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
 password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

 class Meta:
  model = models.UserProfile
  fields = ('email', 'name')

 def clean_password2(self):
  password1 = self.cleaned_data.get("password1")
  password2 = self.cleaned_data.get("password2")
  if password1 and password2 and password1 != password2:
   raise forms.ValidationError("Passwords don't match")
  return password2

 def save(self, commit=True):
  user = super(UserCreationForm, self).save(commit=False)
  user.set_password(self.cleaned_data["password1"])
  if commit:
   user.save()
  return user


class UserChangeForm(forms.ModelForm):
 """A form for updating users. Includes all the fields on
 the user, but replaces the password field with admin's
 password hash display field.
 """
 password = ReadOnlyPasswordHashField()
 class Meta:
  model = models.UserProfile
  fields = ('email', 'password', 'name', 'is_active', 'is_admin')
 def clean_password(self):
  return self.initial["password"]
class UserProfileAdmin(BaseUserAdmin):
 form = UserChangeForm
 add_form = UserCreationForm
 list_display = ('email', 'name', 'is_admin', 'is_staff')
 list_filter = ('is_admin',)
 fieldsets = (
  (None, {'fields': ('email', 'password')}),
  ('Personal info', {'fields': ('name',)}),
  ('Permissions', {'fields': ('is_admin', 'is_active', 'roles', 'user_permissions', 'groups')}),
 )
 add_fieldsets = (
  (None, {
   'classes': ('wide',),
   'fields': ('email', 'name', 'password1', 'password2')}
   ),
 )
 search_fields = ('email',)
 ordering = ('email',)
 filter_horizontal = ('groups', 'user_permissions','roles')

2.Django允许您通过AUTH_USER_MODEL配置来引用自定义的model设置来覆盖默认User模型,这个配置的配置方法为在 settings 中加入:AUTH_USER_MODEL = "APP.model_class" ,例如本例中我们需要在 setting 中加入以下配置:

AUTH_USER_MODEL = "app1.UserProfile"

3.部署

python manage.py makemigrations
python manage.py migrate

创建一个新用户,此时我们就可以用这个用户来登录 admin 后台了

python manage.py createsuperuser

效果如下:

Django自定义用户认证示例详解 

自定义认证

那如果我们需要使用我们自己的认证系统呢,假如我们有一个 login 页面和一个 home 页面:

from django.shortcuts import render, HttpResponse, redirect
from django.contrib.auth import authenticate,login,logout
from app1 import models
from django.contrib.auth.decorators import login_required

def auth_required(auth_type):
 # 认证装饰器
 def wapper(func):
  def inner(request, *args, **kwargs):
   if auth_type == 'admin':
    ck = request.COOKIES.get("login") # 获取当前登录的用户
    if request.user.is_authenticated() and ck:
     return func(request, *args, **kwargs)
    else:
     return redirect("/app1/login/")
  return inner
 return wapper

def login_auth(request):
 # 认证
 if request.method == "GET":
  return render(request, 'login.html')

 elif request.method == "POST":
  username = request.POST.get('username', None)
  password = request.POST.get('password', None)
  user = authenticate(username=username, password=password)
  if user is not None:
   if user.is_active:
    login(request, user)
    _next = request.GET.get("next",'/crm')
    return redirect('_next')
   else:
    return redirect('/app1/login/')
  else:
   return redirect('/app1/login/')
 else:
  pass
def my_logout(request):
 # 注销
 if request.method == 'GET':
  logout(request)
  return redirect('/app1/login/')

@login_required
def home(request):
 # home page
 path1, path2 = "Home", '主页'
 if request.method == "GET":
  return render(request, 'home.html', locals())
 elif request.method == "POST":
  pass

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
python的urllib模块显示下载进度示例
Jan 17 Python
Python 执行字符串表达式函数(eval exec execfile)
Aug 11 Python
python编程开发之类型转换convert实例分析
Nov 13 Python
详解Python中的Descriptor描述符类
Jun 14 Python
分享Python开发中要注意的十个小贴士
Aug 30 Python
python利用dir函数查看类中所有成员函数示例代码
Sep 08 Python
Flask框架实现给视图函数增加装饰器操作示例
Jul 16 Python
Django 实现图片上传和显示过程详解
Jul 18 Python
Python selenium抓取虎牙短视频代码实例
Mar 02 Python
Python 实现一个计时器
Jul 28 Python
用python计算文件的MD5值
Dec 23 Python
Python调用腾讯API实现人脸身份证比对功能
Apr 04 Python
python如何压缩新文件到已有ZIP文件
Mar 14 #Python
python中format()函数的简单使用教程
Mar 14 #Python
Python批量提取PDF文件中文本的脚本
Mar 14 #Python
深入理解Django的中间件middleware
Mar 14 #Python
python批量设置多个Excel文件页眉页脚的脚本
Mar 14 #Python
浅谈python正则的常用方法 覆盖范围70%以上
Mar 14 #Python
Python使用matplotlib绘制多个图形单独显示的方法示例
Mar 14 #Python
You might like
Thinkphp多文件上传实现方法
2014/10/31 PHP
thinkphp中空模板与空模块的用法实例
2014/11/26 PHP
php中instanceof 与 is_a()区别分析
2015/03/03 PHP
PHP生成json和xml类型接口数据格式
2015/05/17 PHP
深入解析PHP的Laravel框架中的event事件操作
2016/03/21 PHP
php与python实现的线程池多线程爬虫功能示例
2016/10/12 PHP
PHP实现的简单路由和类自动加载功能
2018/03/13 PHP
使用laravel指定日志文件记录任意日志
2019/10/17 PHP
jquery 多行滚动代码(附详细解释)
2010/06/17 Javascript
jquery的ajax()函数传值中文乱码解决方法介绍
2012/11/08 Javascript
jquery实现的随机多彩tag标签随机颜色和字号大小效果
2014/03/27 Javascript
javascript实现单击和双击并存的方法
2014/12/13 Javascript
javascript通过获取html标签属性class实现多选项卡的方法
2015/07/27 Javascript
限制只能输入数字的实现代码
2016/05/16 Javascript
AngularJS API之copy深拷贝详解及实例
2016/09/14 Javascript
AngularJS 单元测试(一)详解
2016/09/21 Javascript
js以分隔符分隔数组中的元素并转换为字符串的方法
2016/11/16 Javascript
基于Bootstrap漂亮简洁的CSS3价格表(附源码下载)
2017/02/28 Javascript
vue使用$emit时,父组件无法监听到子组件的事件实例
2018/02/26 Javascript
对vuejs的v-for遍历、v-bind动态改变值、v-if进行判断的实例讲解
2018/08/27 Javascript
对Tensorflow中的变量初始化函数详解
2018/07/27 Python
浅谈python之高阶函数和匿名函数
2019/03/21 Python
Python多进程方式抓取基金网站内容的方法分析
2019/06/03 Python
Python何时应该使用Lambda函数
2019/07/02 Python
Tensorflow中tf.ConfigProto()的用法详解
2020/02/06 Python
使用Python实现批量ping操作方法
2020/05/06 Python
美国标志性加大尺码时装品牌:Ashley Stewart
2016/12/15 全球购物
迪奥美国官网:Dior美国
2019/12/07 全球购物
面向对象编程的优势是什么
2015/12/17 面试题
外企财务年会演讲稿
2014/01/03 职场文书
违反学校规定检讨书
2014/01/18 职场文书
医生学习党的群众路线教育实践活动心得体会
2014/11/03 职场文书
产品质量保证书范本
2015/02/27 职场文书
薪资证明范本
2015/06/19 职场文书
2015年高中生国庆节演讲稿
2015/07/30 职场文书
初中军训感言
2015/08/01 职场文书