@

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

Django作为一个完美主义者的终极框架,当然也会想到用户的这些痛点。它内置了强大的用户认证系统--auth,它默认使用 auth_user 表来存储用户数据。

补充:Django内置的生成当前时间的方法

from django.utils.timezone import now
now_time = now() # 生成当前时间
# 时间格式示例:2018-11-22 05:17:09.538525+00:00
# 它生成的时间格式能够与数据库中的auto_now/auto_now_add生成的时间做计算.


#. auth模块

# 导入auth模块
from django.contrib import auth

1. 认证 authenticate()

提供了用户认证功能,即验证用户名以及密码是否正确,一般需要username 、password两个关键字参数。

如果认证成功(用户名和密码正确有效),便会返回一个 User 对象。

authenticate()会在该 User 对象上设置一个属性来标识后端已经认证了该用户,且该信息在后续的登录过程中是需要的。

用法:

# user = auth.authenticate(request, **form_obj.cleaned_data)
user = auth.authenticate(request, username="用户名", password="密码")

2. 登陆 login(HttpRequest, user)

该函数接受一个HttpRequest对象,以及一个经过认证的User对象。

该函数实现一个用户登录的功能。它本质上会在后端为该用户生成相关session数据。

session数据表名为:django_session,一个浏览器对应一条记录。

示例:


3. 注销 logout(request)

该函数接受一个HttpRequest对象,无返回值。

当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。

示例:


4. 认证判断 is_authenticated()

用来判断当前请求是否通过了认证(用户是否登陆)。

示例:


5. 登陆校验 login_requierd()

auth 给我们提供的一个装饰器工具,用来快捷的给某个视图添加登录校验。

若用户没有登录,则会跳转到django默认的登录URL '/accounts/login/ ' ,并传递当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。

如果需要自定义登录的URL,则需要在settings.py文件中通过LOGIN_URL进行修改,如下:

# 修改默认的登陆URL为'/login/':
LOGIN_URL = '/login/'

用法:

# 用于验证是否登陆的装饰器
from django.contrib.auth.decorators import login_required @login_required
def home(request):
pass

6. 创建普通用户 create_user()

auth 提供的一个创建新用户的方法,需要提供必要参数(username、password)等。

示例:


7. 创建超级用户 create_superuser()

auth 提供的一个创建新的超级用户的方法,需要提供必要参数(email, username, password)。

示例:


8. 密码校验 check_password(password)

auth 提供的一个检查密码是否正确的方法,需要提供当前请求用户的密码。

密码正确返回True,否则返回False。

示例:


9. 修改密码 set_password(new_password)

auth 提供的一个修改密码的方法,接收 要设置的新密码 作为参数。

注意:设置完一定要调用用户对象的save方法!!!

示例:



User对象的属性

重要属性:

  • username:用户名
  • password:密文密码
  • is_staff:用户是否拥有网站的管理权限(是否可登陆admin后台).
  • is_active:是否允许用户登陆,设置为False后,可以在不删除用户的前提下禁止用户登陆.

    对禁用的用户调用auth.authenticate()方法将返回None

request.user.xx :返回xx字段的值(xx可以为auth_user表中的所有字段名).

request.user :默认返回username字段的值.



扩展默认的auth_user表

这内置的认证系统这么好用,但是auth_user表字段都是固定的那几个,我在项目中没法拿来直接使用啊!

比如,我想要加一个存储用户手机号的字段,怎么办?

聪明的你可能会想到新建另外一张表然后通过一对一和内置的auth_user表关联,这样虽然能满足要求但是有没有更好的实现方式呢?

答案是当然有了。

我们可以通过继承内置的 AbstractUser 类,来定义一个自己的Model类。

这样既能根据项目需求灵活的设计用户表,又能使用Django强大的认证系统了。

from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
"""
用户信息表
"""
nid = models.AutoField(primary_key=True)
phone = models.CharField(max_length=11, null=True, unique=True) def __str__(self):
return self.username

注意:

按上面的方式扩展了内置的auth_user表之后,一定要在settings.py中告诉Django,我现在使用我新定义的UserInfo表来做用户认证。写法如下:

# 引用Django自带的User表,继承使用时需要设置
AUTH_USER_MODEL = app名.UserInfo'

再次注意:

一旦我们指定了新的认证系统所使用的表,我们就需要重新在数据库中创建该表,而不能继续使用原来默认的auth_user表了。



auth实现

实现功能:注册用户、登陆、注销、修改密码、登陆校验

settings.py文件增加配置项:

# 这里配置项目登陆页面的路由
LOGIN_URL = '/login/'

urls.py文件:

from django.conf.urls import url
from django.contrib import admin
from blog import views urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^register/$', views.register),
url(r'^login/$', views.login),
url(r'^index01/$', views.index01),
url(r'^index02/$', views.index02),
url(r'^logout/$', views.logout),
url(r'^change_password/$', views.change_password),
url(r'^ajax_register/$', views.ajax_register),
]

forms.py文件:

from django import forms
from django.forms import Form
from django.forms import widgets
from django.core.exceptions import ValidationError # 用于抛出错误信息 # 用户登陆验证
class LoginForm(Form):
username = forms.CharField(
label="用户名",
min_length=2,
max_length=6,
error_messages={
'required': "用户名不能为空",
'invalid': "用户名格式错误",
'min_length': "用户名最短2位",
}, # 自定义错误提示
) password = forms.CharField(
label="密码",
min_length=6,
max_length=12,
error_messages={
'required': "密码不能为空",
'invalid': "密码格式错误",
'min_length': "密码最短6位",
},
widget=widgets.PasswordInput(), # 指定input框的type类型password
) # 注册验证
class RegForm(Form):
username = forms.CharField(
label="用户名",
min_length=2,
max_length=6,
error_messages={
'required': "用户名不能为空",
'invalid': "用户名格式错误",
'min_length': "用户名最短2位",
}, # 自定义错误提示
) password = forms.CharField(
label="密码",
min_length=6,
max_length=12,
error_messages={
'required': "密码不能为空",
'invalid': "密码格式错误",
'min_length': "密码最短6位",
},
widget=widgets.PasswordInput(),
) re_password = forms.CharField(
label="确认密码",
min_length=6,
max_length=12,
error_messages={
'required': "验证密码不能为空",
'invalid': "密码格式错误",
'min_length': "密码最短6位",
},
widget=widgets.PasswordInput(),
) def clean_re_password(self, *args, **kwargs):
password = self.cleaned_data.get('password')
re_password = self.cleaned_data.get('re_password')
if password == re_password:
return password
raise ValidationError("密码不一致") # 单选按钮
level = forms.fields.ChoiceField(
label="用户级别",
choices=((0, "普通用户"), (1, "超级用户"),),
initial=0, # 默认选择普通用户
widget=forms.widgets.RadioSelect(),
) # 修改密码
class ChangePwd(Form):
old_password = forms.CharField(
label="旧密码",
min_length=6,
max_length=12,
error_messages={
'required': "旧密码不能为空",
'invalid': "密码格式错误",
'min_length': "密码最短6位",
},
widget=widgets.PasswordInput(),
) password = forms.CharField(
label="新密码",
min_length=6,
max_length=12,
error_messages={
'required': "新密码不能为空",
'invalid': "密码格式错误",
'min_length': "密码最短6位",
},
widget=widgets.PasswordInput(),
) re_password = forms.CharField(
label="确认新密码",
min_length=6,
max_length=12,
error_messages={
'required': "验证密码不能为空",
'invalid': "密码格式错误",
'min_length': "密码最短6位",
},
widget=widgets.PasswordInput(),
) def clean_re_password(self, *args, **kwargs):
password = self.cleaned_data.get('password')
re_password = self.cleaned_data.get('re_password')
if password == re_password:
return password
raise ValidationError("密码不一致")

views.py文件:

from django.shortcuts import render, redirect, HttpResponse
from blog.forms import * # 导入自定义的Form组件
from django.contrib import auth # 导入认证模块
from django.contrib.auth.models import User # 导入User表
from django.contrib.auth.decorators import login_required # 用于验证是否登陆的装饰器
from blog072 import settings # 注册
def register(request):
form_obj = RegForm()
if request.method == 'POST':
form_obj = RegForm(request.POST)
if form_obj.is_valid():
form_obj.cleaned_data.pop('re_password')
level = form_obj.cleaned_data.pop('level')
# 判断要注册的用户类型
if not int(level):
# 使用create()方法创建的用户为明文密码,无法登陆(不可使用此方法)
# User.objects.create(**form_obj.cleaned_data)
# create_user():创建普通用户
User.objects.create_user(is_staff=1, **form_obj.cleaned_data)
# is_staff=1:允许登陆后台(默认不允许)
else:
# create_superuser():创建超级用户
User.objects.create_superuser(email='', **form_obj.cleaned_data)
return redirect('/login/')
return render(request, 'register.html', {'form': form_obj}) # 登陆
def login(request):
form_obj = LoginForm()
if request.method == 'POST':
form_obj = LoginForm(request.POST)
if form_obj.is_valid():
# 只有执行了is_valid之后,才可执行cleaned_data方法,且cleaned_data内的数据是经过校验的
user = auth.authenticate(request, **form_obj.cleaned_data)
# 如果校验成功,user是当前登陆用户对象,否则为None(用户被禁用[is_active=0]后,也会返回None)
if user:
# 生成session数据(表名:django_session 一个浏览器对应一条session数据)
auth.login(request, user)
# 如果是跳转过来的,则登陆成功后返回至原页面:
next = request.GET.get('next')
ret = next if next else '/index01/'
return redirect(ret)
print(form_obj.cleaned_data)
return HttpResponse("用户名或密码错误")
return render(request, 'login.html', {'form': form_obj}) @login_required
def index01(request):
print("用户%s进入index01页面" % request.user)
# request.user.xx :xx可以为auth_user表中的所有字段名
# request.user 默认返回username字段
return render(request, 'index01.html') def index02(request):
if not request.user.is_authenticated():
# is_authenticated():判断当前请求是否通过了认证
ret = '%s?next=%s' % (settings.LOGIN_URL, request.path)
return redirect(ret)
print("用户%s进入index02页面" % request.user)
return render(request, 'index02.html') # 注销
@login_required
def logout(request):
# 注销,清除session数据
auth.logout(request)
return redirect('/login/') # 修改密码
@login_required
def change_password(request):
form_obj = ChangePwd()
if request.method == 'POST':
form_obj = ChangePwd(request.POST)
if form_obj.is_valid():
old_password = form_obj.cleaned_data.get('old_password')
password = form_obj.cleaned_data.get('password')
# 判断旧密码是否正确
if request.user.check_password(old_password):
# 修改密码
request.user.set_password(password)
request.user.save() # 同步到数据库
return redirect('/login/')
return HttpResponse("旧密码错误!")
return render(request, 'change_password.html', {'form': form_obj}) # ajax判断用户名是否存在
def ajax_register(request):
username = request.GET.get('username')
print(username)
print(User.objects.filter(username=username).exists())
if User.objects.filter(username=username).exists():
return HttpResponse("0")
return HttpResponse()

HTML文件:

注册页面(register.html):

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="content-Type" charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
<title>我是注册页面</title>
</head>
<body>
<form action="" method="post" novalidate>
{% csrf_token %}
<p id="sign01">
{{ form.username.label }}
{{ form.username }}
<span style="color: red">{{ form.username.errors.0 }}</span>
<span id="sign02" style="color: red"></span>
</p>
<p>
{{ form.password.label }}
{{ form.password }}
<span style="color: red">{{ form.password.errors.0 }}</span>
</p>
<p>
{{ form.re_password.label }}
{{ form.re_password }}
<span style="color: red">{{ form.re_password.errors.0 }}</span>
</p>
<p>
{{ form.level.label }}
{{ form.level }}
</p>
<p>
<button>注册</button>
<span style="font-size: 50%;">注册成功将返回登陆页面</span>
</p>
</form>
{% load static %}
<script src="{% static 'jquery-3.3.1.js' %}"></script>
<script>
var $UserName = $('#sign01 input');
var $Button = $('button');
$UserName.on('input', function () {
$.ajax({
url: '/ajax_register/',
type: 'GET',
data: {
username: $UserName.val(),
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
},
success: function (data) {
if (data === '0') {
$Button.attr('disabled', 'disabled');
$('#sign02').text("用户名已存在");
} else {
$Button.removeAttr('disabled', 'disabled');
$('#sign02').text('');
}
},
});
});
</script>
</body>
</html>

登陆页面(login.html):

{# bootstrap版登陆页面 #}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="content-Type" charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
{# 需要下载bootstrap样式文件 #}
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
<title>我是登陆页面</title>
</head>
<body>
<form class="form-horizontal" action="" method="post" novalidate>
{% csrf_token %}
<div class="form-group">
<label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">用户名</label>
<div class="col-sm-10">
{{ form.username }}
{# has-error:Form组件要想展示红色错误信息,必须要加这个类 #}
<div class="has-error">
<span class="help-block">{{ form.username.errors.0 }}</span>
</div>
</div>
</div>
<div class="form-group">
<label for="{{ form.password.id_for_label }}" class="col-sm-2 control-label">密码</label>
<div class="col-sm-10 has-error">
{{ form.password }}
<div class="has-error">
<span class="help-block">{{ form.password.errors.0 }}</span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">登陆</button>
<a href="/register/" class="btn btn-sm">注册用户</a>
</div>
</div>
</form>
</body>
</html>

index01.py页面:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="content-Type" charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
<title>index01</title>
</head>
<body>
<h1>我是 Index01 页面</h1>
<a href="/logout/">注销</a>
<a href="/change_password/">修改密码</a>
</body>
</html>

index02.py页面:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="content-Type" charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
<title>index02</title>
</head>
<body>
<h1>我是 Index02 页面</h1>
<a href="/logout/">注销</a>
<a href="/change_password/">修改密码</a>
</body>
</html>

修改密码页面(change_password.html):

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="content-Type" charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
<title>我是修改密码页面</title>
</head>
<body>
<form action="" method="post" novalidate>
{% csrf_token %}
<p>
{{ form.old_password.label }}
{{ form.old_password }}
<span style="color: red">{{ form.odl_password.errors.0 }}</span>
</p>
<p>
{{ form.password.label }}
{{ form.password }}
<span style="color: red">{{ form.password.errors.0 }}</span>
</p>
<p>
{{ form.re_password.label }}
{{ form.re_password }}
<span style="color: red">{{ form.re_password.errors.0 }}</span>
</p>
<p>
<button>提交</button>
<span style="font-size: 50%;">修改成功后将返回登陆页面</span>
</p>
</form>
</body>
</html>

【Django】认证系统的更多相关文章

  1. Django认证系统auth认证

    使用Django认证系统auth认证 auth认证系统可以处理范围非常广泛的任务,且具有一套细致的密码和权限实现.对于需要与默认配置不同需求的项目,Django支持扩展和自定义认证;会将用户信息写入到 ...

  2. django认证系统 Authentication

    Django自带一个用户认证系统,用于处理用户账户.群组.许可和基于cookie的用户会话. Django的认证系统包含了身份验证和权限管理两部分.简单地说,身份验证用于核实某个用户是否合法,权限管理 ...

  3. django 认证系统--3

    WEB request中的认证 django使用sessions和middleware和reqeust对象联系在一起 它们通过给每一个reqeust请求添加一个request.user属性来代表当前用 ...

  4. Django认证系统并不鸡肋反而很重要

    在使用django-admin startproject创建项目后,Django就默认安装了一个采用session实现的认证系统.这是Django相比于其他框架的一大特点:自带认证系统,开箱即用.有人 ...

  5. 自定义Django认证系统的技术方案

    Django已经提供了开箱即用的认证系统,但是可能并不满足我们的个性化需求.自定义认证系统需要知道哪些地方可以扩展,哪些地方可以替换.本文就来介绍自定义Django认证系统的相关技术细节. 自定义认证 ...

  6. django 认证系统--2

    使用django的认证系统 User 对象 User是认证系统的核心.典型代表是用户和你的站点进行交互还有限制访问.注册用户等等.django认证框架中,只存在一个User类,像'superuser' ...

  7. django 认证系统--1

    django的认证系统提供认证和授权两种功能 认证系统包括如下部分: 1.Users 2.Permissions 主要是以 YES/NO 的形式反映一个用户是否能够做某事 3.Groups:就是对多个 ...

  8. Django认证系统实现的web页面

    结合数据库.ajax.js.Djangoform表单和认证系统的web页面 一:数据模块 扩展了Django中的user表,增加了自定义的字段 from django.db import models ...

  9. django认证系统-user对象(创建,改密,认证)

    User对象 User对象是认证系统的核心.它们通常表示与你的站点进行交互的用户,并用于启用限制访问.注册用户信息和关联内容给创建者等.在Django的认证框架中只存在一种类型的用户,因此诸如'sup ...

  10. Django认证系统

    一.cooie与session 1.1 cookie与session cooie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又要保持状态,因此cookie就是在这样的一个场 ...

随机推荐

  1. CentOS7-1810 系统Samba配置说明

    Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件.SMB(Server Messages Block,信息服务块)通信协议是微软(Microsoft)和英特尔(Intel)在198 ...

  2. DedeCMS让channelartlist支持currentstyle属性

    dedecms默认模板的channelartlist是不支持currentstyle属性的.currentstyle属性在导航中应用的比较多,可以实现循环调用栏目后,当前页<li>标签获得 ...

  3. gitHub上如何设置或者取消电子邮箱提醒

    原文链接:点我 我们正常注册的gitHub一般应该都是电子邮箱的方式,在注册账号时可能选择或者默认给了各种提醒,但是gitHub的邮箱提醒真的就比较烦人了,特别是最近团队开发项目,什么动态都有提醒,就 ...

  4. Linux学习-Ubuntu 18.04-安装图文教程

    Ubuntu(友帮拓.优般图.乌班图)是一个以桌面应用为主的开源GNU/Linux操作系统,Ubuntu 是基于Debian GNU/Linux,支持x86.amd64(即x64)和ppc架构,由全球 ...

  5. caioj 1112 树形动态规划(TreeDP)7:战略游戏

    这道题和上一道题非常相似 这道题是看边,上一道是看点. 但是状态定义不同 看边的话没有不放不安全这种状态 因为当前结点的父亲无法让这颗子树没有看到的边看到 所以这种状态不存在 而上一道题存在不放不安全 ...

  6. Eclipse反编译插件 Enhanced Class Decompiler

    因为jar包中的源码都是经过反编译的,所以需要安装插件才能查看到源码,此处介绍的是 Enhanced Class Decompiler 插件. 打开Eclipse,Help --> Eclips ...

  7. dynamic_cast与能力查询

    在C++里面,dynamic_cast 通常用于横向转换,而不是向上或者向下的转换. 这个常常用于检查某个实例,是否实现了某个接口类,那么就把这个实例,用dynamic_cast来转换成这个接口类的实 ...

  8. linux设备驱动归纳总结(三):4.ioctl的实现

    linux设备驱动归纳总结(三):4.ioctl的实现 一.ioctl的简单介绍: 尽管在文件操作结构体"struct file_operations"中有非常多相应的设备操作函数 ...

  9. 【HDU 5402】Travelling Salesman Problem(构造)

    被某题卡SB了,结果这题也没读好...以为每一个格子能够有负数就当搜索做了.怎么想也搜只是去,后来发现每一个格子是非负数,那么肯定就是构造题. 题解例如以下: 首先假设nn为奇数或者mm为奇数,那么显 ...

  10. TortoiseSvn安装的时候,将svn的命令行工具单独隔离出来

    https://stackoverflow.com/questions/2967176/where-is-svn-exe-in-my-machine The subversion program co ...