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如何在django中为用户模型添加自定义权限
Oct 15 Python
详解分布式任务队列Celery使用说明
Nov 29 Python
Python实现的字典排序操作示例【按键名key与键值value排序】
Dec 21 Python
Python HTML解析器BeautifulSoup用法实例详解【爬虫解析器】
Apr 05 Python
解决python彩色螺旋线绘制引发的问题
Nov 23 Python
Python virtualenv虚拟环境实现过程解析
Apr 18 Python
python实现秒杀商品的微信自动提醒功能(代码详解)
Apr 27 Python
如何在python中判断变量的类型
Jul 29 Python
多个版本的python共存时使用pip的正确做法
Oct 26 Python
python 爬取腾讯视频评论的实现步骤
Feb 18 Python
python实现发送邮件
Mar 02 Python
tensorboard 可视化之localhost:6006不显示的解决方案
May 22 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
《PHP编程最快明白》第五讲:php目录、文件操作
2010/11/01 PHP
8个PHP数组面试题
2015/06/23 PHP
[原创]php常用字符串输出方法分析(echo,print,printf及sprintf)
2016/07/09 PHP
ThinkPHP使用getlist方法实现数据搜索功能示例
2017/05/08 PHP
Laravel 5使用Laravel Excel实现Excel/CSV文件导入导出的功能详解
2017/10/11 PHP
layui框架实现文件上传及TP3.2.3(thinkPHP)对上传文件进行后台处理操作示例
2018/05/12 PHP
PHP优化之批量操作MySQL实例分析
2020/04/23 PHP
jQuery中end()方法用法实例
2015/01/08 Javascript
Seajs是什么及sea.js 由来,特点以及优势
2016/10/13 Javascript
JavaScript中清空数组的方法总结
2016/12/02 Javascript
js中的触发事件对象event.srcElement与event.target详解
2017/03/15 Javascript
JS简单判断字符在另一个字符串中出现次数的2种常用方法
2017/04/20 Javascript
jquery插件开发之选项卡制作详解
2017/08/30 jQuery
原生JS实现 MUI导航栏透明渐变效果
2017/11/07 Javascript
Vue.js 踩坑记之双向绑定
2018/05/03 Javascript
基于JavaScript实现一个简单的Vue
2018/09/26 Javascript
Vue.js递归组件实现组织架构树和选人功能案例分析
2019/07/03 Javascript
JS几个常用的函数和对象定义与用法示例
2020/01/15 Javascript
微信小程序间使用navigator跳转传值问题实例分析
2020/03/27 Javascript
基于vue3.0.1beta搭建仿京东的电商H5项目
2020/05/06 Javascript
Python中itertools模块用法详解
2014/09/25 Python
python向已存在的excel中新增表,不覆盖原数据的实例
2018/05/02 Python
python读取文本绘制动态速度曲线
2018/06/21 Python
python爬虫基础之urllib的使用
2020/12/31 Python
css 如何让背景图片拉伸填充避免重复显示
2013/07/11 HTML / CSS
科颜氏加拿大官方网站: Kiehl’s加拿大
2016/08/16 全球购物
JD Sports比利时官网:英国领先的运动鞋和运动服饰零售商
2018/10/10 全球购物
Currentbody法国:健康与美容高科技产品
2020/08/16 全球购物
演讲稿怎么写才完美
2014/01/02 职场文书
公司面试感谢信
2014/02/01 职场文书
网络编辑岗位职责范本
2014/02/10 职场文书
信息技术教学反思
2014/02/12 职场文书
幼儿园秋季开学寄语
2014/08/02 职场文书
礼貌问候语大全
2015/11/10 职场文书
新学期开学寄语2016
2015/12/04 职场文书
2019职场单身人才调研报告:互联网行业单身比例最高
2019/08/07 职场文书