阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

高阶应用-用户验证

248次阅读
没有评论

共计 9518 个字符,预计需要花费 24 分钟才能阅读完成。

一、说明

User 是 auth 模块中维护用户信息的关系模式(继承了 models.Model), 数据库中该表被命名为 auth_user

二、User 表的 SQL 描述

CREATE TABLE "auth_user" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"password" varchar(128) NOT NULL, "last_login" datetime NULL,
"is_superuser" bool NOT NULL,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL,
"email" varchar(254) NOT NULL,
"is_staff" bool NOT NULL,
"is_active" bool NOT NULL,
"date_joined" datetime NOT NULL,
"username" varchar(30) NOT NULL UNIQUE
)

导入

from django.contrib.auth.models import User

三、用户模型属性方法

  • is_staff

    Boolean。决定用户是否可以访问 admin 管理界面。默认 False

  • is_active

    Boolean。用户是否活跃, 默认 True。一般不删除用户,而是将用户的 is_active 设为 False

  • is_authenticated()

    用户是否通过验证,登陆

    request.user.is_authenticated() 可以判断当前用户是否登录

    登录则为 True 否则为 False

  • make_password(password)

    给密码加密 django 自带的加密功能是 hash 加盐

  • check_password(password)

    检查用户输入的密码是否正确

  • set_password(password)

    修改用户密码

  • authenticate() 认证用户名和密码是否正确

    authenticate(username=username, password=password)

    使用

    from django.contrib.auth import authenticate
    
  • create_user() 创建用户

    使用系统 User 模型

    from django.contrib.auth.models import User
    User.objects.create_user(username, email, password)
  • request.user 获取当前登录用户对象

    request.user.username 获取当前登录用户的用户名

  • last_login 自动保存 不需要自己添加代码

    上一次的登录时间,为 datetime 对象,默认为当时的时间。

    user.last_login = timezone.now()

  • request.user.username

    获取当前登录用户的用户名

  • login_required 设置视图函数必须登录才允许访问

    from django.contrib.auth.decorators import login_required
    @login_required(login_url='/') # 没有登录则跳转到首页
    def center(request):
    return Httpresponse('个人中心')
  • login 登录

  • logout 退出登录

四、注册

  • 模板 register.html

    <!DOCTYPE html>
    <html>
    <head>
    <title>注册页面</title>
    <style>
    .pg_header{position: fixed;
    height: 48px;
    top: 0;
    left: 0;
    right: 0;
    background-color: #2459a2;
    line-height: 48px;
    }
    .pg_header .logo{margin: 0 auto;
    float: left;
    width: 200px;
    text-align: center;
    line-height: 48px;
    font-size: 28px;
    color: white;
    }
    .pg_dl{left: 400px;
    display: inline-block;
    padding: 0 40px;
    color: white;
    }
    .pg_header .pg_dl:hover{background-color: #2459fb;
    cursor: pointer;
    }
    .left{margin-top: 20px;
    width: 400px;
    display: inline-block;
    float: left;
    }
    .pg_body{margin-top: 50px;
    font-size: 18px;
    display: inline-block;
    width: 200px;
    }
    .pg_body .menu{width: 800px;
    padding: 15px;
    float: left;
    font-weight: bold;
    }
    input[type="text"]{width: 200px;
    height: 25px;
    border-radius: 6px;
    }
    input[type="password"]{width: 200px;
    height: 25px;
    border-radius: 6px;
    }
    input[type="button"]{background-color: #555555;
    border: none;
    color: white;
    padding: 12px 29px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 17px;
    margin: 4px 2px;
    cursor: pointer;
    border-radius: 4px;
    }
    input[type="submit"]{background-color: #555555;
    border: none;
    color: white;
    padding: 12px 29px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 17px;
    margin: 4px 2px;
    cursor: pointer;
    border-radius: 4px;
    }
    .kong{margin-top: -54px;
    margin-left: 200px;
    float:left;
    padding: 15px;
    }
    .img{width: 50px;
    height: 40px;
    }
    .can{width: 1220px;
    height: 40px;
    line-height: 40px;
    margin: 0 auto;
    text-align: center;
    display: inline-block;
    }
    .tian{color: red;
    float: right;
    font-size: 12px;
    margin-right: -120px;
    margin-top: -25px;
    }
    </style>
    </head>
    <body id="i88" style="margin: 0">
    <div class = "pg_header">
    <a class = "logo">LOGO</a>
    <a class="pg_dl" id="i77">注册</a>
    </div>
    <form name="tijiao" method="post" onsubmit="return check()" action="{% url'App:register'%}">
    {% csrf_token %}
    <div class="left"></div>
    <div class="pg_body">
    <div class="menu">用户名:</div>
    <div class="kong">
    <input id="text1" type="text" name="username" placeholder="请输入用户名" onblur="check()"><span id="div1" class="tian" style="margin-top: 4px">*(为必填)</span>
    </div>
    <div class="menu">密码:</div>
    <div class="kong">
    <input id="text2" type="password" name="userpass" onblur="check()">
    <span id="div2" class="tian" style="margin-top: 5px">*(为必填)</span>
    </div>
    <div class="menu">确认密码:</div>
    <div class="kong">
    <input id="text3" type="password" name="01" onblur="check()">
    <span id="div3" class="tian" style="margin-top: 5px">*(为必填)</span>
    </div>
    <div class="menu">邮箱地址:</div>
    <div class="kong">
    <input id="text4" type="text" name="email" onblur="check()" required>
    <span id="div4" class="tian" style="margin-top: 5px">*(为必填)</span>
    </div>
    </div>
    <div class="can">
    <input id="i111" type="submit" name="002" value="注 册">
    <p style="width: 200px;display: inline-block;"></p>
    <input id="i222" type="button" name="004" value="取 消">
    </div>
    </form>
    <script type="text/javascript">
    // 刷新 or 取消
    document.getElementById('i77').onclick = function(){location.reload();
    }
    document.getElementById('i222').onclick = function(){location.reload();
    }
    // 用户名验证
    function checkname(){var div = document.getElementById("div1");
    div.innerHTML = "";
    var name1 = document.tijiao.text1.value;
    if (name1 == "") {
    div.innerHTML = "用户名不能为空!";
    document.tijiao.text1.focus();
    return false;
    }
    if (name1.length < 4 || name1.length > 16) {
    div.innerHTML = "长度 4 -16 个字符";
    document.tijiao.text1.select();
    return false;
    }
    var charname1 = name1.toLowerCase();
    for (var i = 0; i < name1.length; i++) {var charname = charname1.charAt(i);
    if (!(charname >= 0 && charname <= 9) && (!(charname >= 'a' && charname <= 'z')) && (charname != '_')) {
    div.innerHTML = "用户名包含非法字符";
    document.form1.text1.select();
    return false;
    }
    }
    return true;
    }
    // 密码验证
    function checkpassword(){var div = document.getElementById("div2");
    div.innerHTML = "";
    var password = document.tijiao.text2.value;
    if (password == "") {
    div.innerHTML = "密码不能为空";
    {#document.tijao.text2.focus();#}
    return false;
    }
    if (password.length < 4 || password.length > 16) {
    div.innerHTML = "密码长度为 4 -16 位";
    document.tijiao.text2.select();
    return false;
    }
    return true;
    }
    function checkrepassword(){var div = document.getElementById("div3");
    div.innerHTML = "";
    var password = document.tijiao.text2.value;
    var repass = document.tijiao.text3.value;
    if (repass == "") {
    div.innerHTML = "密码不能为空";
    document.tijiao.text3.focus();
    return false;
    }
    if (password != repass) {
    div.innerHTML = "密码不一致";
    document.tijiao.text3.select();
    return false;
    }
    return true;
    }
    // 邮箱验证
    function checkEmail(){var div = document.getElementById("div4");
    div.innerHTML = "";
    var email = document.tijiao.text4.value;
    var sw = email.indexOf("@", 0);
    var sw1 = email.indexOf(".", 0);
    var tt = sw1 - sw;
    if (email.length == 0) {
    div.innerHTML = "邮箱不能为空";
    document.tijiao.text5.focus();
    return false;
    }
    if (email.indexOf("@", 0) == -1) {
    div.innerHTML = "必须包含 @符号";
    document.tijiao.text5.select();
    return false;
    }
    if (email.indexOf(".", 0) == -1) {
    div.innerHTML = "必须包含. 符号";
    document.tijiao.text5.select();
    return false;
    }
    if (tt == 1) {
    div.innerHTML = "@和. 不能一起";
    document.tijiao.text5.select();
    return false;
    }
    if (sw > sw1) {
    div.innerHTML = "@符号必须在. 之前";
    document.tijiao.text5.select();
    return false;
    }
    else {return true;}
    return ture;
    }
    function check(){if (checkname() && checkpassword() && checkrepassword() && checkEmail()) {return true;}
    else {return false;}
    }
    </script>
    </body>
    </html>
  • views.py

    from django.conf import settings # 导入配置
    from django.shortcuts import render,HttpResponse,redirect,reverse
    from django.contrib.auth.models import User # 导入系统 User 模型
    from django.contrib.auth import login,authenticate
    # 使用系统用户模型 以及方法 进行登录注册 退出登录等处理
    def register(req):
    if req.method == 'POST':
    # 接受表单传递过来的数据
    username = req.POST.get('username')
    userpass = req.POST.get('userpass')
    email = req.POST.get('email')
    try:
    # 用户的创建
    User.objects.create_user(username,email,userpass)
    except:
    return HttpResponse('注册失败')
    return HttpResponse('注册成功')
    return render(req,'register.html')

五、认证用户

  • 导入

    from django.contrib.auth import login,authenticate
    

    login 处理用户登录状态的方法

    authenticate 认证用户的用户名和密码是否正确 正确返回用户对象 否则 None

  • 视图函数

    from django.conf import settings # 导入配置
    from django.shortcuts import render,HttpResponse,redirect,reverse
    from django.contrib.auth.models import User # 导入系统 User 模型
    from django.contrib.auth import login,authenticate
    # 用户认证 登录
    def Login(req):
    if req.method == 'POST':
    username = req.POST.get('username')
    userpass = req.POST.get('userpass')
    user = authenticate(username=username,password=userpass)
    # 认证成功返回对象 否则 None
    if user:
    # 处理登录状态的维持
    login(req,user)
    # 重定向到首页
    return redirect(reverse('App:index'))
    else:
    return redirect(reverse('App:Login'))
    return render(req,'login.html')

    注意:如果该用户 is_active 为 False 则认证失败

  • 在模板中判断是否登录

    Django 自带的用户认证授权系统

    如果用户已经授权成功,说明用户已经登录成功,那么在渲染 index.html 的时候,直接展示已登录状态即可;如果用户认证失败,说明没有登录,那么在渲染 index.html 的时候,直接展示登录表单即可

    {% if request.user.is_authenticated %}
    <h3>登录了欢迎{{request.user.username}}</h3>
    {% else %}
    <h3>没登录</h3>
    {% endif %}

六、修改用户密码

  • 方法

    set_password(new_password)

  • 说明

    修改密码是 User 的实例方法, 该方法不验证用户身份

    user.set_password(new_password)
    
  • 通常该方法需要和 authenticate 配合使用

    user = auth.authenticate(username=username, password=old_password)
    if user is not None:
    user.set_password(new_password)
    user.save()

七、视图函数获取登录用户对象

# 在视图函数中获取登录用户的数据
def own(req):
# 判断是否登录
if req.user.is_authenticated:
print(req.user.username) # 获取登录的用户名
print(req.user.last_login) # 上次登录时间
return HttpResponse('在视图函数中获取登录用户的数据')

八、退出登录

logout 会移除 request 中的 user 信息, 并刷新 session

from django.contrib.auth import logout
def logout_view(request):
logout(request)
return redirect(reverse('App:index'))

九、权限判断(只允许登录用户访问)

@login_required修饰器修饰的 view 函数会先通过 session key 检查是否登录, 已登录用户可以正常的执行操作, 未登录用户将被重定向到 login_url 指定的位置。若未指定 login_url 参数, 则重定向到settings.LOGIN_URL

# 在视图函数中获取登录用户的数据
# 当前的 own 视图函数 必须登录才能访问
# @login_required(login_url='/system_login/')
@login_required # 没有指定 login_url 则会重定向到 settings.py 中指定的 LOGIN_URL 的路由地址
def own(req):
# 判断是否登录
if req.user.is_authenticated:
print(req.user.username) # 获取登录的用户名
print(req.user.last_login) # 上次登录时间
return HttpResponse('在视图函数中获取登录用户的数据')

配置全局 就不用再每一个装饰器添加了

settings.py

LOGIN_URL =‘/login/’

十、自定义用户表

  • 给 auth_user 的模型表添加新字段 iphon 和 icon 字段

  • models.py

    from django.contrib.auth.models import AbstractUser
    class User(AbstractUser):
    iphone = models.CharField(max_length=11,default=15611833906)
    icon = models.CharField(max_length=40,default='default.jpg')
  • 将用户模型设置为自己的模型

    AUTH_USER_MODEL = 'App.User'
    

    将迁移文件 和 库删除 在重新执行迁移

  • 添加自定义用户认证

    在 App 下新建一个 auth.py

    auth.py

    from django.contrib.auth.backends import ModelBackend
    from django.db.models import Q
    from App.models import User
    class MyBackend(ModelBackend):
    def authenticate(self, username=None, password=None, **kwargs):
    user = User.objects.filter(Q(username=username)|Q(iphone=username)|Q(email=username)).first()
    if user:
    if user.check_password(password):
    return user
    return None

    注意:

    当认证失败的时候返回值只能为 None 否则报错

  • 在 settings.py 添加如下代码

    AUTHENTICATION_BACKENDS = ('App.auth.MyBackend',
    )
  • 视图代码更改为

    from App.models import User
    u = User.objects.create_user(username,email,userpass,iphone='18826123687')

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-05-26发表,共计9518字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中