1、本身实现登陆验证
2、Django自带的用户验证模块——auth
3、本身动手解决auth不足的地方
1、本身实现登陆验证
需求:一共有index和login两个页面,若是用户没有登陆访问index页面,则会自动跳转到login页面进行登陆,用户在login登陆以后,会跳转到index页面,页面出现欢迎用户字样
分析:数据库和session相结合,能够实现不一样用户显示不一样欢迎字样。不过本身写装饰器太多麻烦,并且若是用户多的话session的验证重复步骤就比较多
1.写入函数
#views.py
from functools import wraps
def check_login(f):
@wraps(f) #取消装饰器装饰完成以后,函数名称改变的问题
def inner(request, *args, **kwargs):
if request.session.get("is_login") == "1": # 若是session中(is_login)对应的value为1,就执行f()函数,不然,返回登陆页面
return f(request, *args, **kwargs)
else:
return redirect("/login/")
return inner
def login(request):
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password") #从html中拿到用户输入的帐号和密码
user = models.User.objects.filter(username=username, password=password) # 从数据库中拿到帐号和密码和用户输入一致的数据
if user: #若是有,则证实用户帐号密码正确,若是没有,就返回登陆页面
# 登录成功
request.session["is_login"] = "1" #为此次登陆设置一个session,key为is_login,value为'1'
# request.session["username"] = username
request.session["user_id"] = user[0].id # 为此次登陆设置一个session,key为username,value为数据库中本帐号密码保存的id
# 写上面的一条代码,django后台自动作的事情
# 1. 生成特殊的字符串
# 2. 特殊字符串当成key,在数据库的session表中对应一个session value
# 3. 在响应中向浏览器写了一个Cookie Cookie的值就是 特殊的字符串
return redirect("/index/")
return render(request, "login.html")
@check_login #装饰器,检测用户是否登陆,若是登陆,就执行index函数,若是没有,就跳转到登陆页面
def index(request):
user_id = request.session.get("user_id")
# 根据id去数据库中查找用户
user_obj = models.User.objects.filter(id=user_id) # 设置session的时候,把数据库中的id设为了session中的key,目的就是在这里再次获得id,从数据库中拿出其它数据
if user_obj:
return render(request, "index.html", {"user": user_obj[0]})
else:
return render(request, "index.html", {"user": "匿名用户"})
2.补充index.html页面
# index.html
<!DOCTYPE html>
<html>
<head>
<title>index</title>
</head>
<body>
<h3>This is a test page!</h3>
hello,{{ user.username }}! # 替换登陆的名字
</body>
</html>
3.建立数据表
# models.py
class User(models.Model):
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=20, null=False)
password = models.CharField(max_length=20, null=False)
2、Django自带的用户验证模块——auth
在使用这个被前辈们封装好的模块以前,咱们仍是先来学习一下模块的基本使用方法吧!
1.建立超级用户
python manage.py createsuperuser
# 超级用户数据表(auth_user)是django自动帮忙建立的,可是不能够直接往里面写入数据哦!
# 由于直接写入的话,密码是明文显示的,而通常来讲,密码须要以加密形式保存到数据库中
# 如:username='username', password='$MqFtX/a3inUsPdJekYDMh8H4ZkohfCl3Lc4Vj5jZuNI='
2.authenticate()
from django.contrib import auth #导入auth模块
# 验证用户名和密码,若是验证成功,获得的是一个用户对象,若是验证失败,获得的是匿名用户,取它的任意字段都是空
auth.authenticate(username='theuser',password='thepassword')
若是认证信息有效,会返回一个 User 对象。authenticate()会在User 对象上设置一个属性来标识后端已经认证了该用户,且该信息在后续的登陆过程当中是须要的。
3.login(HttpRequest, user)
auth.login(request, user)
# 将验证的用户注入request.user属性
# 该函数接受一个HttpRequest对象,以及一个认证了的User对象
# 此函数使用django的session框架给某个已认证的用户附加上session id等信息。
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
...
else:
# Return an 'invalid login' error message.
...
4.logout(request) 注销用户
# 该函数接受一个HttpRequest对象,无返回值。
# 当调用该函数时,当前请求的session信息会所有清除。
# 该用户即便没有登陆,使用该函数也不会报错。
from django.contrib.auth import logout
def logout_view(request):
logout(request)
# Redirect to a success page.
5.user对象的 is_authenticated()
要求:
1 用户登录后才能访问某些页面,
2 若是用户没有登陆就访问该页面的话直接跳到登陆页面
3 用户在跳转的登录界面中完成登录后,自动访问跳转到以前访问的地址
方法1:
def my_view(request):
if not request.user.is_authenticated():
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
方法2:
from django.contrib.auth.decorators import login_required
@login_required # django已经为咱们设计好了一个用于此种状况的装饰器:login_requierd()
def my_view(request):
...
# 若用户没有登陆,则会跳转到django默认的登陆URL '/accounts/login/ '
# 默认url能够在settings.py文件中经过LOGIN_URL进行修改(
在settings.py中加入 LOGIN_URL = '/login/'
)
# 登录成功后,会重定向到该路径
注意:
1. 若是是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经经过了认证。经过认证并不意味着用户拥有任何权限,这个方法甚至也不检查该用户是否处于激活状态,只是代表用户成功的经过了认证。
2. 这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登陆,若是true则能够向前台展现request.user.name
6.使用create_user辅助函数建立用户
def register(request):
from django.contrib.auth.models import User
user = User.objects.create_user(username='abcd', password='999999999') # 这里把它写死了,实际中要从页面中post过来,获得用户输入的帐号和密码
# user = User.objects.create_user(username='',password='',email='') # email能够不写,password至少8个字符,password用哈希算法保存到数据库
# 这里建立用户一共有三种:1. create() 密码明文保存; 2. create_superuser() 建立超级用户 3. create_user() 建立普通用户
return HttpResponse('successful!')
7.使用check_password(passwd)检查密码
def register(request):
from django.contrib.auth.models import User
user_obj = User.objects.create_user(username='abcd', password='999999999')
user_obj.check_password('888888888') # --->返回false
user_obj.check_password('999999999') # --->返回true,为了演示,这里一样也把数值给写死了
8.使用 set_password() 来修改密码
user = User.objects.get(username='') # 获得要修改密码的对象
user.set_password(password='') # 从新设置密码
user.save() # 保存
3、auth_user字段不够的解决方案
1.一对一表
from django.contrib.auth.models import User
class UserDetail(models.Model):
phone = models.CharField(max_length=11)
user = models.OneToOneField(to=User) #这里关联的User就是上面导入的User
2.类的继承(继承auth_user表)
from django.contrib.auth.models import User,
AbstractUser
class UserInfo(AbstractUser):
phone = models.CharField(max_length=11)
# 若是使用继承的方式,须要在settings.py中配置 默认用户认证时使用的是哪张表
# AUTH_USER_MODEL = 'app01.UserInfo'
# 另外使用这种方法以前,要把auth本身建立的user表删除才能够
# 做用:替代auth_user并扩展功能
4、未处理的两点内容
is_staff : 用户是否拥有网站的管理权限.
is_active : 是否容许用户登陆, 设置为``False``,能够不用删除用户来禁止 用户登陆
简单示例
def sign_up(request):
state = None
if request.method == 'POST':
password = request.POST.get('password', '')
repeat_password = request.POST.get('repeat_password', '')
email=request.POST.get('email', '')
username = request.POST.get('username', '')
if User.objects.filter(username=username):
state = 'user_exist'
else:
new_user = User.objects.create_user(username=username, password=password,email=email)
new_user.save()
return redirect('/book/')
content = {
'state': state,
'user': None,
}
return render(request, 'sign_up.html', content)
注册示例代码
@login_required
def set_password(request):
user = request.user
state = None
if request.method == 'POST':
old_password = request.POST.get('old_password', '')
new_password = request.POST.get('new_password', '')
repeat_password = request.POST.get('repeat_password', '')
if user.check_password(old_password):
if not new_password:
state = 'empty'
elif new_password != repeat_password:
state = 'repeat_error'
else:
user.set_password(new_password)
user.save()
return redirect("/log_in/")
else:
state = 'password_error'
content = {
'user': user,
'state': state,
}
return render(request, 'set_password.html', content)