• python相关注册登录方式


    1、使用django自带功能实现登录/退出登录

     使用django自带登录功能,前提生成用户(用户注册)使用的是django自带的user,或称models中用户表继承于django自带的user

    1.1、登录

     views.py:

    from django.contrib.auth import authenticate,login,logout
    
    def acc_login(request):
        """登录页面"""
        error_msg = ''
        if request.method == "POST":
            username = request.POST.get('username')
            password = request.POST.get('password')
            user = authenticate(username = username, password = password)
    
            if user:
                login(request,user)
                return redirect(request.GET.get('next','/index/')) # 如果有next则跳转到next指定的页面,如果没有则跳转到index页面
    
            else:
                error_msg = "Wrong username or password!"
    
        return render(request,"login.html",{'error_msg':error_msg})

    1.2、退出登录

     views.py:

    def acc_logout(request):
        logout(request)
        return redirect("/login/")

     urls.py:

    from django.urls import path
    from NBCRM import views
    
    urlpatterns = [
    
        path('login/',views.acc_login),
        path('logout/',views.acc_logout,name="logout"),
    
    ]

     settings.py:

      当某些页面设置了登录才能访问时,用户访问该页面会失败,此时可以在settings中进行下面的设置,指定用户在未登录前访问需登录才能访问的页面时,跳转到指定(登录)页面,执行某些操作,成功后才能访问目标页面。

    LOGIN_URL = '/login/'

     登录界面:

     


     2.自定义登录方式

    1)login相关代码:

    def login(request):
        if request.method == "POST":
            username = request.POST.get("username")
            password = request.POST.get("password")
    
            user = models.User.objects.filter(username=username, password=password)  # [User Obj, ]
            if user:
                # 登陆成功
                request.session["is_login"] = "1"
                # request.session["username"] = username
                request.session["user_id"] = user[0].id
                # 1. 生成特殊的字符串
                # 2. 特殊字符串当成key,在数据库的session表中对应一个session value
                # 3. 在响应中向浏览器写了一个Cookie Cookie的值就是 特殊的字符串
    
                return redirect("/index/")
    
        return render(request, "login.html")

    2)check_login:

     装饰器,用于检查用户是否登录

    from functools import wraps
    def check_login(f):
        @wraps(f)
        def inner(request, *args, **kwargs):
            if request.session.get("is_login") == "1":
                return f(request, *args, **kwargs)
            else:
                return redirect("/login/")
        return inner

    3)index:

     首页,访问前判断用户是否已登录,登录则成功访问,未登录则跳转登录页面

    @check_login
    def index(request):
        user_id = request.session.get("user_id")
        # 根据id去数据库中查找用户
        user_obj = models.User.objects.filter(id=user_id)
        if user_obj:
            return render(request, "index.html", {"user": user_obj[0]})
        else:
            return render(request, "index.html", {"user": "匿名用户"})

    2.1、session简单介绍

    1)session作用

    1. 生成随机字符串
    2. 写到用户浏览器的cookie中
    3. 保存到session中
    4. 在随机字符串对应的字典中设置相关内容

    2)session默认过期时间为2周,如果自己设置过期时间,自定义设置过期时间优先级高于默认时间

    request.session.set_expiry(value)  # 设置session过期时间

     默认的过期时间是两周,如果自己设置了过期时间,这样自己设定的优先级就会高于默认的

     如果value是个整数,session会在些秒数后失效。

     如果value是个datatime或timedelta,session就会在这个时间后失效。

     如果value是0,用户关闭浏览器session就会失效。

     如果value是None,session会依赖全局session失效策略。

    3)session的相关配置

    # settings.py
    SESSION_COOKIE_NAME = "sessionid"      # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    
    SESSION_COOKIE_PATH = "/"              # Session的cookie保存的路径(默认)
    
    SESSION_COOKIE_DOMAIN = None             # Session的cookie保存的域名(默认)
    
    SESSION_COOKIE_SECURE = False          # 是否Https传输cookie(默认)
    
    SESSION_COOKIE_HTTPONLY = True         # 是否Session的cookie只支持http传输(默认)
    
    SESSION_COOKIE_AGE = 1209600             # Session的cookie失效日期(2周)(默认)
    
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False    # 是否关闭浏览器使得Session过期(默认)
    
    SESSION_SAVE_EVERY_REQUEST = False        # 是否每次请求都保存Session,默认修改之后才保存(默认)

    4)Django中对应session的存储方式

    Django中支持session,其中内部提供了5种类型的session供开发者使用:

    • 数据库(默认)
    • 缓存
    • 文件
    • 缓存+数据库
    • 加密cookie
    1、如果是数据库,需要在settings.py中配置如下:
    
    SESSION_ENGINE = 'django.contrib.sessions.backends.db' (引擎(默认))
    
    2、如果是缓存session,需要在settings.py中配置如下:
    
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'(引擎)
    
    SESSION_CACHE_ALIAS= 'default'  使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
    
    3、 如果是文件session, 需要在settings.py中配置如下:
    
    SESSION_ENGINE = 'django.contrib.sessions.backends.file' (引擎)
    
    SESSION_FILE_PATH=None  缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()   
    
    4、如果是缓存+数据库session,需要在settings.py中配置如下:
    
    SESSION_ENGINE='django.contrib.sessions.backends.cached_db'       (引擎)

     3、利用django自带登录功能,实现自定义用户名或邮箱登录,及用户注册(邮箱激活)、忘记密码等功能

      3.1 实现用户注册功能 

     

      3.1.1 验证码实现 --第三方库:Captcha

       1)安装captcha

    pip install  django-simple-captcha

      2)在我们项目的setting.py中的INSTALLED_APPS注册captcha。需要注意的是,在INSTALLED_APPS中注册的,都需要经过makemigrations、migrate生成对应的表数据

    INSTALLED_APPS = [
        ……
        'captcha',
        ……
    ]

      3)配置urls.py

    from django.urls import path,include,re_path
    
    
    urlpatterns = [
        # 验证码
        re_path(r'^captcha', include('captcha.urls')), 
    ]

    通过上述几步,我们就能在项目中正常使用captcha了。用法很简单:

      1)后台用到验证码的地方:

    from captcha.fields import CaptchaField
    
    class RegisterForm(forms.Form):
        """注册表单验证"""
    
        captcha = CaptchaField(error_messages={'invalid':'验证码错误'})

      2)前端页面展示 --关于验证码:

    
    
    <label>验&nbsp;证&nbsp;码</label>
    {{ register_form.captcha }}

    使用captcha实现验证码的好处:不需要我们判断前端验证码输入与原验证码是否一致(内部已实现了判断),只需要按上述几个步骤操作,即可实现注册/登录页面的验证码验证功能

     3.1.2 实现注册功能

      结合第三方库captcha,实现附有验证码的注册功能

      1)注册功能 --form表单验证 

    from django import forms
    from django.core.exceptions import ValidationError
    
    from captcha.fields import CaptchaField
    
    class RegisterForm(forms.Form):
        """注册表单验证"""
        email = forms.EmailField(required=True)
        password = forms.CharField(required=True,min_length=6)
        # 验证码 内部已经包含判断验证码是否正确,不需要进行下述的验证码验证代码编写
        captcha = CaptchaField(error_messages={'invalid':'验证码错误'})
    
        # 验证码验证,使用第三方库captcha时不需要再判断,属于画蛇添足
        # def clean_captcha(self):
        #     print("captcha:",self.request.session.get('code'))
        #     print("valid_code:",self.cleaned_data.get('code'))
        #     if self.request.session.get('code').upper() == self.cleaned_data.get('code').upper():
        #         return self.cleaned_data['code']
        #     else:
        #         raise ValidationError('验证码不正确')
        # 自定义方法(局部钩子),密码必须包含字母和数字
        def clean_password(self):
            if self.cleaned_data.get('password').isdigit() or self.cleaned_data.get('password').isalpha():
                raise ValidationError('密码必须包含数字和字母')
            else:
                return self.cleaned_data['password']
    
        # 自定义方法(全局钩子, 检验两个字段),可用于检验两次密码是否一致;
        # def clean(self):
        #     if self.cleaned_data.get('password') != self.cleaned_data.get('password2'):
        #         raise ValidationError('密码不一致')
        #     else:
        #         return self.cleaned_data
    forms.py

      2)views.py:

    def register(request):
        """用户注册 """
        if request.method == "POST":
            register_form = forms.RegisterForm(request.POST)
            if register_form.is_valid():
                user_name = request.POST.get('email',None)
                if UserProfile.objects.filter(email=user_name):
                    # 用户已经存在,不需要再注册
                    return render(request,'register.html',{'msg':'用户已经存在','register_form':register_form})
                pass_word = request.POST.get('password', None)
                # 将密码加密后再保存
                pass_word = make_password(pass_word)
                UserProfile.objects.create(
                    username=user_name,
                    email=user_name,
                    is_active=False,
                    password=pass_word
                )
                email_send_status = email_send.send_register_email(user_name, 'register')  # 发送邮件,用于用户激活账号
                if email_send_status: # 状态为1,表示邮件发送成功
                    email_send_success = True  # 用于前端判断发送邮件的类型
                    return render(request,'send_email_success.html',locals())
            else:
                # status_form = True #用于前端注册时判断是否填充客户输入原数据
                return render(request, 'register.html', {'msg':'用户名或密码格式错误','register_form':register_form})
    
        else:
            register_form = forms.RegisterForm()
            return render(request,'register.html',locals())

      3)urls.py配置:

    from django.urls import path
    from web_online import views
    
    urlpatterns = [
    
        path('register/',views.register, name='register'),
        # 验证码url
        re_path(r'^captcha',include('captcha.urls')),
    
    ]

      4)HTML前端代码(仅供参考):

    <!DOCTYPE html>
    {% load staticfiles %}
    <html>
    
    <head>
        <meta charset="UTF-8">
        <meta name="renderer" content="webkit">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
        <title>慕学在线注册</title>
        <link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
        <link rel="stylesheet" type="text/css" href="{% static 'css/login.css' %}">
    
    </head>
    <body>
    <div class="loginbox dialogbox">
        <h1>账号登录</h1>
        <div class="close jsCloseDialog"><img src="{% static 'images/dig_close.png' %}"/></div>
        <div class="cont">
            <form id="jsLoginForm" autocomplete="off">
                <div class="box">
                    <span class="word3">用户名</span>
                    <input type="text" name="account_l" id="account_l" placeholder="手机号/邮箱" />
                </div>
                <div class="box">
                    <span class="word2">密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</span>
                    <input type="password" name="password_l" id="password_l" placeholder="请输入您的密码"/>
                </div>
                <div class="error btns login-form-tips" id="jsLoginTips"></div> <!--登录错误提示-->
                <div class="btns">
                    <span><input type="checkbox" id="jsAutoLogin" />&nbsp;自动登录</span>
                    <span class="forget btn fr">忘记密码</span>
                </div>
                <div class="button">
                    <input type="button" value="登录" id="jsLoginBtn" />
                </div>
                <div class="btns">
                    <span class="fr">没有账号?<span class="regist btn">立即注册</span></span>
                </div>
            </form>
        </div>
    </div>
    <div class="dialog" id="jsDialog">
        <!--提示弹出框-->
        <div class="successbox dialogbox" id="jsSuccessTips">
            <h1>成功提交</h1>
            <div class="close jsCloseDialog"><img src="{% static 'images/dig_close.png' %}"/></div>
            <div class="cont">
                <h2>您的需求提交成功!</h2>
                <p></p>
            </div>
        </div>
        <div  class="noactivebox dialogbox" id="jsUnactiveForm" >
            <h1>邮件验证提示</h1>
            <div class="close jsCloseDialog"><img src="{% static 'images/dig_close.png' %}"/></div>
            <div class="center">
                <img src="{% static 'images/send.png' %}"/>
                <p>我们已经向您的邮箱<span class="green" id="jsEmailToActive">12@13.com</span>发送了邮件,<br/>为保证您的账号安全,请及时验证邮箱</p>
                <p class="a"><a class="btn" id="jsGoToEmail" target="_blank" href="http://mail.qq.com">去邮箱验证</a></p>
                <p class="zy_success upmove"></p>
                <p style="display: none;" class="sendE2">没收到,您可以查看您的垃圾邮件和被过滤邮件,也可以再次发送验证邮件(<span class="c5c">60s</span>)</p>
                <p class="sendE">没收到,您可以查看您的垃圾邮件和被过滤邮件,<br/>也可以<span class="c5c green" id="jsSenEmailAgin" style="cursor: pointer;">再次发送验证邮件</span></p>
            </div>
        </div>
    </div>
    
    <div class="bg" id="dialogBg"></div>
    <header>
        <div class="c-box fff-box">
            <div class="wp header-box">
                <p class="fl hd-tips">慕学在线,在线学习平台!</p>
                <ul class="fr hd-bar">
                    <li>服务电话:<span>4001008031</span></li>
                    <li><a href="{% url 'login' %}">[登录]</a></li>
                    <li class="active"><a href="{% url 'register' %}">[注册]</a></li>
                </ul>
            </div>
        </div>
    </header>
    <section>
        <div class="c-box bg-box">
            <div class="login-box clearfix">
                <div class="hd-login clearfix">
                    <a class="index-logo" href="/index/"></a>
                    <h1>用户注册</h1>
                    <a class="index-font" href="/index/">回到首页</a>
                </div>
                <div class="fl slide">
                    <div class="imgslide">
                        <ul class="imgs">
    
                            <li><a href=""><img width="483" height="472" src="{% static 'images/57a801860001c34b12000460.jpg' %}" /></a></li>
    
                            <li><a href=""><img width="483" height="472" src="{% static 'images/57a801860001c34b12000460.jpg' %}" /></a></li>
    
                            <li><a href=""><img width="483" height="472" src="{% static 'images/57a801860001c34b12000460.jpg' %}" /></a></li>
    
                        </ul>
                    </div>
                    <div class="unslider-arrow prev"></div>
                    <div class="unslider-arrow next"></div>
                </div>
                <div class="fl form-box">
                    <div class="tab">
                        <!--<h2 class="active">手机注册</h2>-->
                        <h2>邮箱注册</h2>
                    </div>
    
                    <div class="tab-form">
                        <form id="email_register_form" method="post" action="{% url 'register' %}" autocomplete="off">
                        {% csrf_token %}
                            <div class="form-group marb20 {% if register_form.errors.email.0 %} errorput {% endif %}">
                                <label>邮&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;箱</label>
                                <input  type="text" id="id_email" name="email" {% if register_form.email.value %} value="{{ register_form.email.value }}" {% endif %} placeholder="请输入您的邮箱地址" />
                            </div>
                            <div class="error btns" id="jsEmailTips">{{ register_form.errors.email.0 }}</div>
                            <div class="form-group marb8 {% if register_form.errors.password.0 %} errorput {% endif %}">
                                <label>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</label>
                                <input type="password" id="id_password" name="password"  {% if register_form.password.value %} value="{{ register_form.password.value }}" {% endif %} placeholder="请输入6-20位非中文字符密码" />
                            </div>
                            <div class="error btns" id="jsEmailTips">{{ register_form.errors.password.0 }}</div>
                            <div class="form-group marb8 captcha1 {% if register_form.errors.captchal.0 %} errorput {% endif %}">
    {#                            <label>验&nbsp;证&nbsp;码</label>#}
    {#                            {{ register_form.captcha }}#}
                                <input name='code' type="text" placeholder="验证码" />
                                {{ register_form.captcha }}
                            </div>
                            <div class="error btns" id="jsEmailTips">{{ register_form.errors.captcha.0 }}</div>
                            <div class="error btns" id="jsEmailTips">
                                {{ msg }}
                            </div>
                            <div class="auto-box marb8">
                            </div>
                            <input class="btn btn-green" id="jsEmailRegBtn" type="submit" value="注册" />
    
                        </form>
                    </div>
                    <p class="form-p">已有账号?<a href="{% url 'login' %}">[立即登录]</a></p>
                </div>
            </div>
        </div>
    </section>
    
    <input id="isLogin" type="hidden" value="False"/>
    <script src="{% static 'js/jquery.min.js' %}" type="text/javascript"></script>
    <script src="{% static 'js/unslider.js' %}" type="text/javascript"></script>
    <script src="{% static 'js/validateDialog.js' %}"  type="text/javascript"></script>
    <script src="{% static 'js/login.js' %}"  type="text/javascript"></script>
    </body>
    </html>
    register.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        {% if email_send_success %}
            <p>【注册账号激活】邮件已发送,请移步邮箱中查收!</p>
        {% else %}
            <p>【密码重置】邮件已发送,请移步邮箱中查收!</p>
        {% endif %}
    
    </body>
    </html>
    send_email_success.html

     3.1.3  注册账号激活 

      在上述注册功能实现过程中涉及到邮件激活账号:email_send.send_register_email(user_name,'register') , 下面实现注册账号激活功能

       注意:用户账号激活时,本质是通过is_active=True来实现的,如果将is_staff也设置为True,则表示该用户可以登录我们项目的django后台。切记,只有is_active、is_staff同时为True,才能登录django后台。

      1)email_send.py:用于给用户发送邮件,实现下述功能

    • 账号激活
    • 忘记密码,重置密码
    • 修改密码
    import random
    from users.models import EmailVerifyRecord
    from django.core.mail import send_mail
    from web_online import settings
    
    def random_str(random_length=16):
        """默认生成16位随机字符串"""
        str = ''
        # 生成字符串的可选字符串
        chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
        length = len(chars) - 1
        # ran_dom = random.Random()
        for i in range(random_length):
            str += chars[random.randint(0, length)]
        return str
    
    # 发送邮件
    def send_register_email(email, send_type="register"):
        """
        发送邮件
        发送前将当前注册用户保存到数据库,方便后台激活账号时能在数据库中找到对应的注册用户
        """
        if send_type == 'update_email': # 修改密码操作
            code = random_str(4)
    
        else:
            code = random_str(16)
    
        # 保存到数据库
        EmailVerifyRecord.objects.create(
            code=code,
            email=email,
            send_type=send_type
        )
    
        # 定义邮箱内容:
        if send_type == "register":  # 注册激活账号
            subject = "Mx在线教育注册激活链接"  # 标题
            email_body = "请复制打开下面的链接激活你的账号:http://127.0.0.1:8000/active/{0}".format(code)  # 文本邮件体
            sender = settings.DEFAULT_FROM_EMAIL  # 发件人
            receiver = [email]  # 接收人
            email_send_status = send_mail(subject, email_body, sender, receiver)
            return email_send_status
            # if email_send_status:
            #     pass
        elif send_type == 'forget':  # 忘记密码 重置密码
            subject = "Mx在线教育重置密码链接"  # 标题
            email_body = "请复制打开下面的链接重置密码:http://127.0.0.1:8000/reset/{0}".format(code)  # 文本邮件体
            sender = settings.DEFAULT_FROM_EMAIL  # 发件人
            receiver = [email]  # 接收人
            email_send_status = send_mail(subject, email_body, sender, receiver)
            return email_send_status
    
        elif send_type == "update_email":  # 修改密码验证码
            subject = "Mx在线教育邮箱修改验证码"
            email_body = "你的邮箱验证码为{0}".format(code)
            sender = settings.DEFAULT_FROM_EMAIL
            receiver = [email]
    
            # 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,从哪里发,接受者list
            send_status = send_mail(subject, email_body, sender, receiver)
            # 如果发送成功
            if send_status:
                pass
    email_send.py

       2)使用django自带的邮件发送功能,需要在settings.py中配置发送邮件的基本数据:

    # 邮箱配置
    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
    EMAIL_HOST = "smtp.163.com"   #以163邮箱为例,SMTP服务器(邮箱需要开通SMTP服务)
    EMAIL_HOST_PASSWORD = '******'     #SMTP服务授权码
    DEFAULT_FROM_EMAIL = EMAIL_HOST_USER = "13*******@163.com"    #我的163邮箱帐号
    EMAIL_PORT = 25     #163邮箱SMTP服务端口
    EMAIL_USE_TLS = True     # 163、qq邮箱此值为True,aliyun此值为False,163可以忽略此值
    # EMAIL_SUBJECT_PREFIX = '[yshblog.com]'     #邮件标题前缀,默认是'[django]'

      3)views.py:

       注册账号激活功能

    def user_active(request, accode):
        """注册用户账号激活"""
        if request.method == "GET":
            ac_records = EmailVerifyRecord.objects.filter(code=accode)
            if ac_records: # 有当前注册用户
                five_mintes_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
                ac_record = ac_records[0]
                # print("five_mintes_ago:",five_mintes_ago)
                # print("send_time:",ac_record.send_time)
                if five_mintes_ago > ac_record.send_time: # 发送时间超过5分钟,返回链接失效页面
                    return render(request, 'active_fail.html')
    
                ac_email = ac_record.email
                ac_user = UserProfile.objects.get(email=ac_email) # 当前注册用户
                ac_user.is_active = True
                ac_user.save()
                return render(request,'active_success.html',locals())
    
            else:
                return render(request,'active_fail.html')

      4)urls.py配置:

    from django.urls import path
    from web_online import views
    
    urlpatterns = [
    
        re_path(r'^active/(w+)/', views.user_active, name='user_active'),  # 邮箱激活账号
    
    ]

      5)注册成功返回页面、注册用户失败或链接失效返回页面:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>mx教育邮箱注册成功</title>
    </head>
    <body>
    <h3>恭喜!您已成功激活账号:{{ ac_email }}</h3>
    <p style="color: red">点击跳转:<a href="/login/">登录</a></p>
    </body>
    </html>
    active_success.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <p style="color: red;">链接已经失效</p>
    </body>
    </html>
    active_fail.html

    至此,用户注册及激活功能即完成。



     

      3.2 实现自定义用户名或邮箱登录功能

      3.2.1 userProfile继承于 AbstractUser

         需要注意的是:AbstractUser中定义的email字段不具有唯一性,容易造成多个用户使用同一邮箱,当使用邮箱登录时会造成冲突。因此,需要重写email字段,使其与username字段一样,具备 '唯一'性

    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
    class UserProfile(AbstractUser):
        """用户"""
        gender_choices = (
            ('male',''),
            ('female','')
        )
    
        nick_name = models.CharField('昵称',max_length=32 ,default='')
        birthday = models.DateField('生日',null=True,blank=True)
        gender = models.CharField('性别',max_length=8,choices=gender_choices,default='female')
        adress = models.CharField('地址',max_length=100,default='')
        mobile = models.CharField('手机号',max_length=11,null=True,blank=True)
        image = models.ImageField(upload_to='image/%Y/%m',default='image/default.png',max_length=100)
        email = models.EmailField('邮箱', blank=True,unique=True)  # 重写email字段,加上'唯一'标识
    
        class Meta:
            verbose_name = '用户信息'
            verbose_name_plural = verbose_name
    
        def __str__(self):
            return self.username

     此时 userProfile表所存字段:

     

     3.2.2 在views中编写登录功能之前,我们需要先写一个form表单,用于用户登录时,对用户名及密码格式进行验证:

         forms.py/LoginForm

    from django import forms
    
    class LoginForm(forms.Form):
        """登录表单验证"""
        username = forms.CharField(required=True)
        password = forms.CharField(required=True, min_length=6)

      3.2.3 接着在views界面中编写我们的登录代码:

    from django.shortcuts import render,redirect
    from django.contrib.auth import authenticate ,login ,logout
    from users.models import UserProfile
    from web_online import forms
    
    def mx_login(request):
        """登录"""
        login_form = forms.LoginForm()
        if request.method == "POST":
            login_form = forms.LoginForm(request.POST)
            if login_form.is_valid():
                user_name = request.POST.get('username',None)
                pass_word = request.POST.get('password',None)
                user = authenticate(username=user_name, password=pass_word)
                if user:
                    if user.is_active:
                        # 只有注册激活才能登陆
                        login(request,user)
                        return redirect('/index/')
                    else:
                        return render(request,'login.html',{'msg': '用户未激活', 'login_form': login_form})
                else:
                    return render(request, 'login.html', {'msg': '用户名或密码错误', 'login_form': login_form})
            else:
                return render(request, 'login.html', {'msg': '用户名或密码格式错误,请重新输入!', 'login_form': login_form})
    
        return render(request,"login.html")

    简单解析:

     1. is_active:在注册中,我们对成功激活账号的用户设置is_active为True,在登录操作中就可以通过is_active的状态来判断用户是否是注册成功的用户,来决定是否给用户登录权限

     2. authenticate()方法的验证:我们使用的是django自带的authenticate验证, 默认只对用户名、密码进行验证,我们要使用用户名或邮箱进行验证,需要自定义authenticate方法,实现代码如下:

    class CustomBackend(ModelBackend):
        """
        用于mx_login用户登录验证
        需在settings中配置好authenticate验证方式(即在此进行authenticate的相关验证)
        """
        def authenticate(self, request, username=None, password=None, **kwargs):
            # 重写authenticate方法
            try:
                user = UserProfile.objects.get(Q(username=username)|Q(email=username))
                if user.check_password(password):
                    """
                    1.在注册时,我们对密码使用了加密处理(django下的make_password),因此在登录验证密码时需要先将明文密码加密
                    后才能跟数据库中已加密后的密码进行比较
                    2.check_password()是AbstractUser类中的方法,UserProfile继承于AbstractUser,check_password会加密明文密
                    码后,与数据库密码做对比,再进行判断两密码是否一致
                    3.验证如果为True,表示密码一致;为False,表示密码不一致
                    """
                    return user
                else:
                    return None
    
            except Exception as e:
                return None

     以上基本实现了自定义登录功能验证,但要验证流程中的authenticate验证走我们自定义的authenticate验证,需要在settings.py中配置AUTHENTICATION_BACKENDS ,如不配置,默认会走django自带的authenticate验证:

    AUTHENTICATION_BACKENDS = ( # 登录认证设置
        'web_online.views.CustomBackend', #CustomBackend所在路径
    )

      3.2.4 url配置:

    from django.urls import path
    from web_online import views
    
    urlpatterns = [
    
        path('login/',views.mx_login, name='login'),
    
    ]

      3.2.5 html配置:

       注意:HTML前端代码未附带css、js代码,仅供参考

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8">
        <meta name="renderer" content="webkit">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
        <title>慕学在线网登录</title>
        <link rel="stylesheet" type="text/css" href="/static/css/reset.css">
        <link rel="stylesheet" type="text/css" href="/static/css/login.css">
    </head>
    <body>
    <div class="dialog" id="jsDialog">
    <!--提示弹出框,用于找回密码操作时的提示-->
    <div class="successbox dialogbox" id="jsSuccessTips">
        <h1>成功提交</h1>
        <div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
        <div class="cont">
            <h2>您的需求提交成功!</h2>
            <p></p>
        </div>
    </div>
    <div  class="noactivebox dialogbox" id="jsUnactiveForm" >
        <h1>邮件验证提示</h1>
        <div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
        <div class="center">
            <img src="/static/images/send.png"/>
            <p>我们已经向您的邮箱<span class="green" id="jsEmailToActive">12@13.com</span>发送了邮件,<br/>为保证您的账号安全,请及时验证邮箱</p>
            <p class="a"><a class="btn" id="jsGoToEmail" target="_blank" href="http://mail.qq.com">去邮箱验证</a></p>
            <p class="zy_success upmove"></p>
            <p style="display: none;" class="sendE2">没收到,您可以查看您的垃圾邮件和被过滤邮件,也可以再次发送验证邮件(<span class="c5c">60s</span>)</p>
            <p class="sendE">没收到,您可以查看您的垃圾邮件和被过滤邮件,<br/>也可以<span class="c5c green" id="jsSenEmailAgin" style="cursor: pointer;">再次发送验证邮件</span></p>
        </div>
    </div>
    </div>
    <div class="bg" id="dialogBg"></div>
    <header>
        <div class="c-box fff-box">
            <div class="wp header-box">
                <p class="fl hd-tips">慕学在线网,在线学习平台!</p>
                <ul class="fr hd-bar">
                    <li>服务电话:<span>33333333</span></li>
                    <li class="active"><a href="{% url 'login' %}">[登录]</a></li>
                    <li><a href="{% url 'register' %}">[注册]</a></li>
                </ul>
            </div>
        </div>
    </header>
    <section>
        <div class="c-box bg-box">
            <div class="login-box clearfix">
                <div class="hd-login clearfix">
                    <a class="index-logo" href="/index/"></a>
                    <h1>用户登录</h1>
                    <a class="index-font" href="/index/">回到首页</a>
                </div>
                <div class="fl slide">
                    <div class="imgslide">
                        <ul class="imgs">
                                <li><a href=""><img width="483" height="472" src="/static/images/mysql.jpg"/></a></li>
                            <li><a href=""><img width="483" height="472" src="/static/images/mysql.jpg"/></a></li>
                            <li><a href=""><img width="483" height="472" src="/static/images/mysql.jpg"/></a></li>
                        </ul>
                    </div>
                    <div class="unslider-arrow prev"></div>
                    <div class="unslider-arrow next"></div>
                </div>
                <div class="fl form-box">
                    <h2>帐号登录</h2>
                    <form action="/login/" method="post" autocomplete="off">
                        {% csrf_token %}
                        <div class="form-group marb20 {% if login_form.errors.username.0 %} errorput {% endif %}">
                            <label>用&nbsp;户&nbsp;名</label>
                            <input name="username" id="account_l" type="text" placeholder="手机号/邮箱" {% if login_form.username.value %}value="{{ login_form.username.value }}"{% endif %}/>
                        </div>
                        <div class="error btns login-form-tips" id="jsLoginTips">{{ login_form.errors.username.0 }}</div>
                        <div class="form-group marb8 {% if login_form.errors.password.0 %} errorput {% endif %}">
                            <label>密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</label>
                            <input name="password" id="password_l" type="password" {% if login_form.password.value %}value="{{ login_form.password.value }}"{% endif %} placeholder="请输入您的密码"/>
                        </div>
                        <div class="error btns login-form-tips" id="jsLoginTips">{{ login_form.errors.password.0 }}</div>
                        <div class="error btns login-form-tips" id="jsLoginTips">{{ msg }}</div>
                        <div class="auto-box marb38">
    
                            <a class="fr" href="#">忘记密码?</a>
    {#                        <a class="fr" href="{% url 'forgetpwd' %}">忘记密码?</a>#}
                        </div>
                        <input class="btn btn-green" id="jsLoginBtn" type="submit" value="立即登录 > "/>
                        <input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy'/>
                        {% csrf_token %}
                    </form>
                    <p class="form-p">没有慕学在线网帐号?<a href="{% url 'register' %}">[立即注册]</a></p>
                </div>
            </div>
        </div>
    </section>
    <script src="/static/js/jquery.min.js" type="text/javascript"></script>
    <script src="/static/js/unslider.js" type="text/javascript"></script>
    <script src="/static/js/login.js"  type="text/javascript"></script>
    </body>
    </html>
    login.html


     

     3.3 退出登录功能

        3.3.1 退出登录

         实现退出登录功能很简单,在views.py中编写退出登录代码:

    from django.contrib.auth import logout
    
    def mx_logout(request):
        """退出登录"""
        logout(request)
        return redirect('/login/')  # 返回登录页面

        3.3.2 url配置:

    from django.urls import path
    from web_online import views
    
    urlpatterns = [
    
        path('logout/',views.mx_logout, name='logout'),
    
    ]

    注:退出登录功能,没有HTML前端代码 



    3.4 实现忘记密码、找回密码功能

      点击 [忘记密码],进入找回密码,根据注册邮箱,找回密码

          

     3.4.1 根据注册用户邮箱,发送验证邮件

       1)views.py:

    def forget_pwd(request):
        """忘记密码,通过邮箱找回密码"""
        message = {}
        if request.method == "POST":
            forget_pwd_form = forms.ForgetPwdForm(request.POST)
            if forget_pwd_form.is_valid():
                email = request.POST.get('email',None)
                user_objs = UserProfile.objects.filter(email=email)
                if user_objs:  # 判断邮箱是否存在
                    send_status = email_send.send_register_email(email,'forget')
                    if send_status:  # 邮件发送成功
                        email_send_success = False  # 用于前端判断发送邮件的类型
                        return render(request,'send_email_success.html',locals())
                else:
                    message['msg'] = '该邮箱不存在'
                    message['status'] = True
                    return render(request, 'forgetpwd.html', {'message': message, 'forget_pwd_form': forget_pwd_form})
            else:  # form表单验证不通过
                message['msg'] = '邮箱或验证码错误'
                message['status'] = True
                return render(request,'forgetpwd.html',{'message':message,'forget_pwd_form' : forget_pwd_form})
        else:
            forget_pwd_form = forms.ForgetPwdForm()
        return render(request,'forgetpwd.html',{'forget_pwd_form' : forget_pwd_form})

      2)forms.py 表单验证:

    class ForgetPwdForm(forms.Form):
        """忘记密码"""
        email = forms.EmailField(required=True)
        captcha = CaptchaField(error_messages={'invalid': '验证码错误'})

      3)urls.py:

    from django.urls import path
    from web_online import views
    
    urlpatterns = [
    
        path('forgetpwd/', views.forget_pwd, name='forgetpwd'),  # 忘记密码
    
    ]

      4)HTML前端代码:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8">
        <meta name="renderer" content="webkit">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
        <title>慕学网首页</title>
        <link rel="stylesheet" type="text/css" href="/static/css/reset.css">
        <link rel="stylesheet" type="text/css" href="/static/css/login.css">
    </head>
    <body>
    <!--提示弹出框-->
    <div class="successbox dialogbox" id="jsSuccessTips">
        <h1>成功提交</h1>
        <div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
        <div class="cont">
            <h2>您的需求提交成功!</h2>
            <p></p>
        </div>
    </div>
    <div class="resetpassbox dialogbox" id="jsSetNewPwd">
        <h1>重新设置密码</h1>
        <div class="close jsCloseDialog"><img src="/static/images/dig_close.png"/></div>
        <p class="green">请输入新密码</p>
        <form id="jsSetNewPwdForm">
            <div class="box">
                <span class="word2">密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码</span>
                <input type="password" name="password" id="jsResetPwd" placeholder="请输入新密码"/>
            </div>
            <div class="box">
                <span class="word2">确&nbsp;认&nbsp;密&nbsp;码</span>
                <input type="password" name="password2" id="jsResetPwd2" placeholder="请再次输入新密码"/>
            </div>
            <div class="box">
                <span class="word2">验&nbsp;&nbsp;证&nbsp;&nbsp;码</span>
                <input type="text" name="code" id="jsResetCode" placeholder="请输入手机验证码"/>
            </div>
            <div class="error btns" id="jsSetNewPwdTips"></div>
            <div class="button">
                <input type="hidden" name="mobile" id="jsInpResetMobil"/>
                <input id="jsSetNewPwdBtn" type="button" value="提交"/>
            </div>
        </form>
    </div>
    <div class="bg" id="dialogBg"></div>
    <header>
        <div class="c-box fff-box">
            <div class="wp header-box">
                <p class="fl hd-tips">慕学网,在线学习平台!</p>
                <ul class="fr hd-bar">
                    <li>服务电话:<span>33333333</span></li>
                    <li><a href="{% url 'login' %}">[登录]</a></li>
                    <li class="active"><a href="/forgetpwd/">[忘记密码]</a></li>
                </ul>
            </div>
        </div>
    </header>
    <section>
        <div class="c-box bg-box">
            <div class="login-box clearfix">
                <div class="hd-login clearfix">
                    <a class="index-logo" href="{% url 'index' %}"></a>
                    <h1>忘记密码</h1>
                    <a class="index-font" href="{% url 'index' %}">回到首页</a>
                </div>
                <div class="fl slide">
                    <div class="imgslide">
                        <ul class="imgs">
                            <li><a href=""><img width="483" height="472" src="/static/images/57a801860001c34b12000460.jpg"/></a>
                            </li>
                            <li><a href=""><img width="483" height="472" src="/static/images/57a801860001c34b12000460.jpg"/></a>
                            </li>
                            <li><a href=""><img width="483" height="472" src="/static/images/57a801860001c34b12000460.jpg"/></a>
                            </li>
                        </ul>
                    </div>
                    <div class="unslider-arrow prev"></div>
                    <div class="unslider-arrow next"></div>
                </div>
                <div class="fl form-box">
                    <h2>忘记密码</h2>
                    <form id="jsFindPwdForm" method="post" autocomplete="off">
                    {% csrf_token %}
                        <div class="form-group marb20 {% if forget_pwd_form.errors.email.0 %} errorput {% endif %}">
                            <label>帐&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;号</label>
                            <input type="text" id="account" name="email" {% if message.status %} value="{{ forget_pwd_form.email.value }}" {% endif %} placeholder="请输入邮箱号"/>
                        </div>
                        <div class="form-group captcha1 marb38 {% if forget_pwd_form.errors.captchal.0 %} errorput {% endif %}">
                            <label>验&nbsp;证&nbsp;码</label>
                            {{ forget_pwd_form.captcha }}
                        </div>
                        <div class="error btns" id="jsForgetTips">{{ message.msg }}</div>
                        <input type="hidden" name="sms_type" value="1">
                        <input class="btn btn-green" id="jsFindPwdBtn" type="submit" value="提交"/>
                        <p class="form-p" style="bottom:40px;">您还可以<a href="{% url 'login' %}"> [直接登录]</a></p>
                    </form>
                </div>
            </div>
        </div>
    </section>
    
    <input id="isLogin" type="hidden" value="False"/>
    <script src="/static/js/jquery.min.js" type="text/javascript"></script>
    <script src="/static/js/unslider.js" type="text/javascript"></script>
    <script src="/static/js/validateDialog.js" type="text/javascript"></script>
    <script src="/static/js/login.js" type="text/javascript"></script>
    </body>
    </html>
    forgetpwd.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        {% if email_send_success %}
            <p>【注册账号激活】邮件已发送,请移步邮箱:{{ user_name }} 中查收!</p>
        {% else %}
            <p>【密码重置】邮件已发送,请移步邮箱:{{ email }} 中查收!</p>
        {% endif %}
    
    </body>
    </html>
    send_email_success.html

      5)email_send

       【密码重置】发送邮件的相关代码与用户注册账号激活整合在一起,详见用户注册账号激活 --发送邮件


      3.4.2 重置密码

       1)forms.py:

    class ModifyPwdForm(forms.Form):
        """重置密码"""
        password1 = forms.CharField(required=True, min_length=6)
        password2 = forms.CharField(required=True, min_length=6)
    
        def clean_password1(self):
            if self.cleaned_data.get('password1').isdigit() or self.cleaned_data.get('password1').isalpha():
                raise ValidationError('密码必须包含数字和字母')
            else:
                return self.cleaned_data['password1']

       2)views.py:

    # 确定当前用户邮箱是否正确,如正确转到重置密码页面,进行密码重置
    
    def pwd_reset(request,ac_code):
        """用户重置密码链接"""
        if request.method =="GET":
            records = EmailVerifyRecord.objects.filter(code=ac_code)
            if records:
                email = records[0].email
                return render(request, "password_reset.html", {"email": email})
            else:# 链接不对
                return render(request, "active_fail.html")
    # 重置密码
    
    def modify_pwd(request):
        """重置密码"""
        if request.method == "POST":
            modify_form = forms.ModifyPwdForm(request.POST)
            if modify_form.is_valid():
                pwd1 = request.POST.get("password1", None)
                pwd2 = request.POST.get("password2", None)
                # email数据是从pwd_reset获取到的
                email = request.POST.get("email", None)
                if pwd1 != pwd2:
                    return render(request, "password_reset.html", {"email": email, "msg": "密码不一致!"})
                user = UserProfile.objects.get(email=email)
                user.password = make_password(pwd2)
                user.save()
                return render(request, "login.html")
            else:
                email = request.POST.get("email", None)
                return render(request, "password_reset.html", {"email": email, "modify_form": modify_form})
        else:
            return render(request, 'password_reset.html')

      3)urls.py配置

    from django.urls import path
    from web_online import views
    
    urlpatterns = [
    
        re_path(r'^reset/(w+)/',views.pwd_reset,name='reset'), # 邮箱重置密码链接
        path('modify_pwd/',views.modify_pwd,name='modify_pwd'), # 重置密码
    
    ]

      4)HTML前端代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="renderer" content="webkit">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
        <title>密码修改</title>
        <link rel="stylesheet" type="text/css" href="/static/css/reset.css">
        <link rel="stylesheet" type="text/css" href="/static/css/animate.css">
        <link rel="stylesheet" type="text/css" href="/static/css/style.css">
    
    <body>
    <div class="wp">
        <div class="resetpassword" id="resetPwdForm">
            <h1>修改密码</h1>
            <p>已经通过验证,请设置新密码</p>
            <form id="reset_password_form" action="{% url 'modify_pwd' %}" method="post">
            {% csrf_token %}
                <ul>
                    <li class="{% if modify_form.errors.password1.0 %} errorput {% endif %}">
                        <span class="">新 密 码 :</span>
                        <input type="password" name="password1" id="pwd" placeholder="6-20位非中文字符">
                        <i></i>
                    </li>
                    <input type="hidden" name="email" value="{{ email }}">
                    <li class="{% if modify_form.errors.password2.0 %} errorput {% endif %}">
                        <span class="">再次输入密码 :</span>
                        <input type="password" name="password2" id="repwd" placeholder="6-20位非中文字符">
                        <i></i>
                    </li>
                    <div class="error btns" id="jsPasswdResetTips" style="color: red">
                        {% for key,error in modify_form.errors.items %}{{ key }}:{{ error }}{% endfor %}
                        {{ msg }}
                    </div>
                    <li class="button">
                        <input type="submit" value="提交">
                    </li>
                </ul>
            </form>
        </div>
        <div class="resetpassword" id="reset_password_tips" style="display:none;">
            <h1>修改密码成功,请重新登录</h1>
            <img class="fl" src="/static/images/check2.png">
            <p class="successword">已经成功修改密码,请重新登录</p>
        </div>
    </div>
    </body>
    </html>
    password_reset.html


    未完待续。。

  • 相关阅读:
    Docker配置samba共享
    阿里云SSL 免费证书申请方法
    linux centos7 关闭防火墙的方法
    PHP 面向对象的特性 抽象类和接口
    详解mixphp的依赖注入控制反转
    swoole mixphp swoolefor热更新使用方法
    nginx ab并发测试 apr_socket_recv: Connection refused (111
    PHP golang java 并发测试
    php.ini 添加的模块没更新的解决方法
    关于golang的未来的道路
  • 原文地址:https://www.cnblogs.com/Eric15/p/10216106.html
Copyright © 2020-2023  润新知