django2.1.7从0开始搭建一个个人博客网站第9天

用户登录登出功能

一、用户登录功能实现

1.分析

业务处理流程:

  • 判断用户输入的账号是否为空
  • 判断用户输入的密码是否为空,格式是否正确
  • 判断用户输入的账号与密码是否正确

请求方法POST

url定义/user/login/

请求参数:url路径参数

参数类型前端是否必须传描述
user_account字符串用户输入的账号可以是手机号也可以是用户名
password字符串用户输入的密码
remember_me字符串用户输入的“是否记住我”

注:由于是post请求,在向后端发起请求时,需要附带csrf token

2.后端代码实现

.login接受两个参数,第一个是request对象,第二个是user对象。login方法使用SessionMiddleware将userID存入session当中。注意,在用户还未登录的时候,也存在着匿名用户的Session,在其登陆之后,之前在匿名Session中保留的信息,都会保留下来。这两个方法要结合使用,而且必须要先调用authenticate(),因为该方法会User的一个属性上

1、views.py
# 在user目录下的views.py文件中定义如下类:
import json
import re

from django.shortcuts import render
from django.http import HttpResponse, HttpResponseForbidden
from django.views import View
from django_redis import get_redis_connection
from django.contrib.auth import login

from dj_blog.utils.res_code import res_json,Code
from users.models import User
from users.forms import LoginForm

#登录
class LoginView(View):
    def get(self,request):
        title = '一支穿云箭'
        return render(request,'users/login.html',context={'title':title})

    # is_authenticated  = true   false
    def post(self,request):
        js_str = request.body
        if not js_str:
            return res_json(errno=Code.PARAMERR,errmsg='参数错误')
        dict_data = json.loads(js_str.decode())
        # 数据验证   使用form 表单验证
        form = LoginForm(data=dict_data,request=request)
        if form.is_valid():
            # 表单验证成工处理
            return res_json(errno=Code.OK)
        else:
            # 表单验证失败处理
            msg_list = []
            for i in form.errors.get_json_data().values():
                msg_list.append(i[0].get('message'))
            msg_str = '/'.join(msg_list)
            return res_json(errno=Code.PARAMERR,errmsg=msg_str)
        
2、路由urls.py

from django.urls import path
from . import views
app_name = 'users'
urlpatterns = [

    # path('',views.index),
    path('login/',views.LoginView.as_view(),name='login'),
    path('register/',views.RegisterView.as_view(),name='register'),

]

3、表单forms.py
# 在users目录下的forms.py文件中定义如下类:

import re
from django import forms
from django.contrib.auth import login
from django.db.models import Q

from .models import User
from . import constants

class LoginForm(forms.Form):
    user_account = forms.CharField()
    password = forms.CharField(max_length=20,min_length=6,
                               error_messages={
                                   'min_length':'密码长度大于6',
                                   'max_length':'密码长度小于20',
                                   'required':'密码不能为空'
                               })
    remember = forms.BooleanField(required=False)


    def __init__(self,*a,**k):
        self.request =k.pop('request')
        super().__init__(*a,**k)

    def clean_user_account(self):
        user_info = self.cleaned_data.get('user_account')
        if not user_info:
            raise forms.ValidationError('用户名不能为空')

        if not re.match(r'^1[3-9]\d{9}$]', user_info) and (len(user_info)<5 or len(user_info)>20 ):
            raise forms.ValidationError('输入的用户名格式错误,请重新输入!')
        return user_info

    def clean(self):
        cleaned_data = super().clean()
        user_info = cleaned_data.get('user_account')
        pass_wd= cleaned_data.get('password')
        rmber = cleaned_data['remember']

        # 判断是否是用户名你还是手机号  Q
        user_qs = User.objects.filter(Q(mobile=user_info) | Q(username=user_info))
        if user_qs:
            user = user_qs.first()
            # 判断密码
            if user.check_password(pass_wd):
                if rmber:
                    self.request.session.set_expiry(constants.SESSION_EXPIRY_TIME)
                else:
                    self.request.session.set_expiry(constants.SESSION_TIME)
                login(self.request,user)

            else:
                raise forms.ValidationError('用户名或密码错误,请重新输入')
        else:
            raise forms.ValidationError('用户名不存在,请重新输入!')

        return cleaned_data
4、constants.py
# 在users目录下的constants.py文件中定义如下常量:

# 用户session信息过期时间,单位秒,这是设置为30天
SESSION_EXPIRY_TIME = 30 * 24 * 60 * 60

#不选记住我就只有7天的
SESSION_TIME = 7 * 24 * 60 * 60

3、前端:
1、login.js

$(function () {
    let $login = $('.form-contain');

    $login.submit(function (e) {
        e.preventDefault();
        let sUsername = $('input[name=telephone]').val();

        if(sUsername === ''){
            message.showError('用户名不能为空!');
            return
        }

        if (!(/^[\u4e00-\u9fa5\w]{5,20}$/.test(sUsername))){
            message.showError('请输入5-20位字符的用户名');
            return
        }
        // 密码验证

        let sPassword = $('input[name=password]').val();

        if(!sPassword){
            message.showError('密码不能为空!');
            return
        }

        // 验证用户名  6
        if(sPassword.length<6 || sPassword.length>20) {
            message.showError('密码长度需要在6-20之间');
            return
        }

        let status = $("input[type='checkbox']").is(':checked');

        // g构造参数
        let sData ={
            'user_account' : sUsername,
            'password':sPassword,
            'remember':status
        };

        $.ajax({
            url:'/user/login/',
            type:'POST',
            // headers: {
            //     // 根据后端开启的CSRFProtect保护,cookie字段名固定为X-CSRFToken
            //     "X-CSRFToken": getCookie("csrftoken")
            // },
            data:JSON.stringify(sData),
            contentType:'application/json; charset=utf-8',
            dataType:'json',
        })

            .done(function (res) {
                if(res.errno==='0'){
                    message.showSuccess('贵宾,恭喜您登录成功!');
                    setTimeout(function () {
                        window.location.href = '/';
                    },1500)
                }else {
                    message.showError(res.errmsg)
                }

            })
            .fail(function () {
                message.showError('服务器超时,请重试!')
            })

    })

});

写完login的js后要记得在login页面中引入js
在这里插入图片描述

2、base页面下的common.js
$(()=>{
    let $navLi = $('#header .nav .menu li')
    $navLi.click(function(){
        $(this).addClass('active').siblings('li').removeClass('active')
    });


    // get cookie using jQuery
    function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
      let cookies = document.cookie.split(';');
      for (let i = 0; i < cookies.length; i++) {
        let cookie = jQuery.trim(cookies[i]);
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) === (name + '=')) {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
    }

    function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
            }
        }
    });


});

记得要在base页面下引入common.js

3、html
修改base页面登录逻辑

{% if user.is_authenticated %}
              <div class="author">
                  <i class="PyWhich py-user"></i>
                  <span>{{user.username }}</span>
                  <ul class="author-menu">
                      <li><a href="javascript:void(0);">后台管理</a></li>
                      <li><a href="javascript:void(0);">退出登录</a></li>
                  </ul>
              </div>
          {% else %}
              <div>
              <i class="PyWhich py-user"></i>
              <span>
                  <a href="{% url 'users:login' %}" class="login">登录</a> / <a href="{% url 'users:register' %}"
                                                                          class="reg">注册</a>
              </span>
          </div>
          {% endif %}

如果登录后,会显示用户名
在这里插入图片描述

二、用户登出功能实现

1.分析

请求方法GET

url定义/user/logout/

实现:调用Django自带的logout(request)函数即可

2.后端代码实现

1、views.py

# 在users目录下的views.py文件中定义如下类:

class LogoutView(View):
    """
    """
    def get(self, request):
        logout(request)

        return redirect(reverse("users:login"))

2、urls.py

# 在users目录下的urls.py文件中定义如下路由:

from django.urls import path
from . import views

app_name = 'users'

urlpatterns = [
    path('logout/', views.LogoutView.as_view(), name='logout'),

]
3、前端代码

{% if user.is_authenticated %}
              <div class="author">
                  <i class="PyWhich py-user"></i>
                  <span>{{user.username }}</span>
                  <ul class="author-menu">
                      {% if user.is_staff %}
                        <li><a href="javascript:void(0);">后台管理</a></li>
                      {% endif %}
                        <li><a href="{% url 'users:logout' %}">退出登录</a></li>
                  </ul>
              </div>
          {% else %}
              <div>
              <i class="PyWhich py-user"></i>
              <span>
                  <a href="{% url 'users:login' %}" class="login">登录</a> / <a href="{% url 'users:register' %}"
                                                                          class="reg">注册</a>
              </span>
          </div>
          {% endif %}
总结:
	1、用户登录这次使用了表单进行校验,如何把request对象传入表单中,如何从form.errors取出错误进行拼接。
	2、通过上下文处理器模板中已经传入user对象,可以通过user来判断时是否登录,是否可以用户后台管理功能。
	3、json数据通过request.body进行取值。
	4、这次通过js获得csrf并在请求头中加入了csrf,不用每次ajax都要写这个csrf请求头。(结合前面的中间件生成的csrf)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值