用户登录验证问题及auth模块的引入

一、自己实现登录验证
二、Django自带的用户验证模块——auth
三、自己动手解决auth不足的地方
 
 
 
一、自己实现登录验证

需求:一共有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)
 
 
 
二、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()    # 保存
 
 
 
三、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并扩展功能
 
 
 
 
四、未处理的两点内容

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)
 
修改密码示例
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2018-07-01 18:43  小隐于林i  阅读(2703)  评论(0编辑  收藏  举报