DRF+VUE实现密码与验证码登录

# 一、用户名+密码+jwt验证实现登录验证

下面是VUE前端登录界面部分代码

	

记住密码

忘记密码

// 登录
methods: {
    loginhander() {
      if (this.username == '' || this.password == '') {
        this.$message.error("用户名或密码不能为空")
        return;
      }

      this.$axios.post("http://127.0.0.1:8000/user/authorizations/", {
        "username": this.username,
        "password": this.password
      }).then(response => {
        // 使用浏览器本地存储保存token
        if (this.remember) {
          // 记住登录
          sessionStorage.clear();
          localStorage.token = response.data.token;
          localStorage.id = response.data.id;
          localStorage.username = response.data.username;
        } else {
          // 未记住登录
          localStorage.clear();
          sessionStorage.token = response.data.token;
          sessionStorage.id = response.data.id;
          sessionStorage.username = response.data.username;
        }
        // 页面跳转回到上一个页面 也可以使用 this.$router.push("/") 回到首页
        this.$router.go(-1)

      }).catch(error => {
        this.$message.error("登录失败")
      })
    },
 }

DRF默认已经提供了认证系统Auth模块
注册一个子应用 python …/…/manage.py startapp user
DRF+VUE实现密码与验证码登录_第1张图片
DRF+VUE实现密码与验证码登录_第2张图片
在创建好的子Appuser下models.py中定义用户的用户模型类。
我们自定义的用户模型类还不能直接被Django的认证系统所识别,需要在配置文件中告知Django认证系统使用我们自定义的模型类。
在配置文件中进行设置
DRF+VUE实现密码与验证码登录_第3张图片DRF+VUE实现密码与验证码登录_第4张图片然后执行数据库迁移(必须保证是第一次迁移)
python manage.py makemigrations
python manage.py migrate

接下来安装Django REST framework JWT
在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token认证机制。

安装 pip install djangorestframework-jwt
settings/dev.py,进行配置
DRF+VUE实现密码与验证码登录_第5张图片
也可以手动生成jwt,在用户注册或登录成功后,在序列化器中返回用户信息以后同时返回token即可。

from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)

接下来准备路由
DRF+VUE实现密码与验证码登录_第6张图片登录接口配置完成。接下来可以测试一下。
前端输入用户名和密码
DRF+VUE实现密码与验证码登录_第7张图片

DRF+VUE实现密码与验证码登录_第8张图片

DRF+VUE实现密码与验证码登录_第9张图片obtain_jwt_token会进行用户名和密码的检验,验证通过则登录成功,返回token.
如果想要返回其他信息,则可以进行设置
DRF+VUE实现密码与验证码登录_第10张图片
修改settings/dev.py配置文件
DRF+VUE实现密码与验证码登录_第11张图片DRF+VUE实现密码与验证码登录_第12张图片然后将返回的数据根据需要存储到sessionStorage或者localStorage中

二、多条件登录(默认obtain_jwt_token只能用户名和密码登录),但是我们想实现邮箱+密码和手机号+密码登录

DRF的认证系统在收到用户名与密码时会调用authenticate()验证用户名和密码

authenticate(self, request, username=None, password=None, **kwargs)方法的参数说明:

  • request 本次认证的请求对象
  • username 本次认证提供的用户账号
  • password 本次认证提供的密码

在users/utils.py中编写:

# 增加手机或用户名或者email直接登录功能(用户名/邮箱/手机号 + 密码  )
def get_user_by_account(account):
    """
    根据帐号获取user对象
    :param account: 账号,可以是用户名username,也可以是手机号mobile, 或者其他的数据
    :return: User对象 或者 None
    """
    try:
        user = User.objects.filter(Q(username=account) | Q(mobile=account) | Q(email=account)).first()
    except User.DoesNotExist:
        return None
    else:
        return user


from .models import User
from django.db.models import Q
from django.contrib.auth.backends import ModelBackend


# 增加手机或用户名或者email直接登录功能(用户名/邮箱/手机号 + 密码  )
class UsernameMobileAuthBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        # 此时的username既可以是username,又可以是mobile
        user = get_user_by_account(username)
        # 若查找到User对象,调用User对象的check_password方法检查密码是否正确
        if user is not None and user.check_password(password) and user.is_authenticated:
            return user
        else:
            return None

在配置文件settings/dev.py中告知DRF使用我们自定义的认证后端

AUTHENTICATION_BACKENDS = [
    'user.utils.UsernameMobileAuthBackend',
]

然后就可以实现了。

DRF+VUE实现密码与验证码登录_第13张图片
DRF+VUE实现密码与验证码登录_第14张图片
DRF+VUE实现密码与验证码登录_第15张图片

三、邮箱+验证码登录验证

1.前端发送验证码接口准备

//发送验证码
    sendsms() {
      //邮箱不能为空
      if (this.email == '') {
        this.$message.error("邮箱不能为空")
        return;
      }
      //校验邮箱格式是否正确
      var regEmail = /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
      if (!regEmail.test(this.email)) {
        this.$message.error('邮箱格式不正确')
        return;
      }

      //禁用发送按钮
      this.disabled = true;
      //开启倒计时
      let count = 0;
      let tag = setInterval(() => {
        if (++count >= 60) {
          clearInterval(tag);
          this.disabled = false;
          this.text = "发送验证码";
          return;
        }
        this.text = `${60 - count}秒后获取`;
      }, 1000);


      //校验通过,向后端发送请求(把验证码传给后端)
      this.$axios.get("http://127.0.0.1:8000/user/captcha/", {
        //字典里面套字典传给后端
        params: {
          email: this.email,
        }
      }).then(response => {
        this.$message(response.data.message)
        // console.log(response)
      }).catch(error => {
        //后端返回的字典数据 {"message": "对不起,用户不存在!"} 会存在error.response.data中
        this.$message.error(error.response.data.message)
      })
    },

当邮箱格式都正确时,进行发送请求
DRF+VUE实现密码与验证码登录_第16张图片

后端封装好接口,进行数据接收和校验:
DRF+VUE实现密码与验证码登录_第17张图片视图函数进行校验(get请求用来给手机发送验证码,post请求用来登录验证)
在这里插入图片描述

params: {
email: this.email,
}

class CaptchaAPIView(APIView):

    def get(self, request):
        """获取验证码"""
        email = request.query_params.get("email")
        # 根据email=username查询是否有该用户
        user = get_user_by_account(email)
        if user is None:
            # 请求失败400, {"message": "对不起,用户不存在!"}字典 会返回给前端axios的catch
            return Response({"message": "对不起,用户不存在!"}, status=http_status.HTTP_400_BAD_REQUEST)

        # 邮箱存在,现在进行发送
        code = random.randrange(1000, 9999)
        print("验证码:", code)
        message = "您好!您的注册验证码是{},1分钟内有效,请勿泄露,谨防被骗。".format(code)
        # 发送短信(把code和email传过去)
        smtp_tran(message, email)

        # 验证码 写入redis(django-redis)
        conn = get_redis_connection('default')
        conn.set(email, code, ex=60)

        # 请求成功200,会返回给前端axios的catch
        return Response({"message": "发送成功!"}, status=http_status.HTTP_200_OK)

    def post(self, request):
        """验证码的验证方法"""
        # 1.获取前端传过来的数据
        user = request.data
        # user= {'email': '[email protected]', 'code': '8414'}
        # print("user=", user)

        # 2.对邮箱进行校验
        myuser = get_user_by_account(user['email'])
        if myuser is None:
            # 请求失败400, {"message": "对不起,用户不存在!"}字典 会返回给前端axios的catch
            return Response({"message": "用户邮箱不存在!"}, status=http_status.HTTP_400_BAD_REQUEST)

        # 3.校验验证码
        conn = get_redis_connection()
        redis_code = conn.get(myuser.email)  # 根据邮箱去获取验证码
        # print("redis_code=", redis_code)
        if not redis_code:
            return Response({"message": "验证码失效,请重新发送!"}, status=http_status.HTTP_400_BAD_REQUEST)
        redis_str_code = redis_code.decode('utf-8')

        if user['code'].strip() != redis_str_code:
            return Response({"message": "验证码错误!"}, status=http_status.HTTP_400_BAD_REQUEST)

        # 4.邮箱和验证码校验成功之后,返回token
        payload = jwt_payload_handler(myuser)
        token = jwt_encode_handler(payload)

        return Response({"message": "登录成功!", "username": myuser.username, "id": myuser.id, "token": token},
                        status=http_status.HTTP_200_OK)

smtp_tran(message, email)函数是发送验证码函数,可以单独建一个py文件:

import smtplib

from email.mime.text import MIMEText


def smtp_tran(message, email):
    msg = MIMEText(message, 'html', 'utf-8')
    HOST = 'smtp.qq.com'
    SUBJECT = '邮箱验证码'
    FROM = '发送的邮件@qq.com'
    TO = email   # 接收的邮件
    msg['Subject'] = SUBJECT
    msg['From'] = FROM
    msg['To'] = TO

    server = smtplib.SMTP_SSL(HOST, 465)
    server.login(FROM, '你的授权码')  # 授权码
    server.sendmail(FROM, [TO], msg.as_string())
    server.quit()

然后测试一下:前端输入框输入qq邮箱进行发送:
DRF+VUE实现密码与验证码登录_第18张图片DRF+VUE实现密码与验证码登录_第19张图片

DRF+VUE实现密码与验证码登录_第20张图片

然后进行邮箱登录:http://127.0.0.1:8000/user/captcha/ 接口地址


smsloginhander() {
      //不能为空
      if (this.email == '' || this.code == '') {
        this.$message.error("邮箱或者验证码不能为空")
        return;
      }
      //校验邮箱格式是否正确
      var regEmail = /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
      if (!regEmail.test(this.email)) {
        this.$message({
          message: '邮箱格式不正确',
          type: 'error'
        })
        return;
      }

      //校验通过,向后端发送请求
      this.$axios.post("http://127.0.0.1:8000/user/captcha/", {
        "email": this.email,
        "code": this.code
      }).then(response => {
        // 验证码通过以后,才发送账号和密码进行登录(当邮箱和验证码都成功后,然后再次调用jwt登录验证)
        //后端传过来的数据{"message": "登录成功!", "username": myuser.username, "id": myuser.id, "token": token}
        localStorage.clear();
        sessionStorage.clear();
        sessionStorage.token = response.data.token;
        sessionStorage.id = response.data.id;
        sessionStorage.username = response.data.username;
        // this.$message(response.data.message)
        this.$router.push("/")
      }).catch(error => {
        // console.log("error.response=", error.response)
        this.$message.error(error.response.data.message)
      })

后端接收数据进行校验:

    def post(self, request):
        """验证码的验证方法"""
        # 1.获取前端传过来的数据
        user = request.data
        # user= {'email': '[email protected]', 'code': '8414'}
        # print("user=", user)

        # 2.对邮箱进行校验
        myuser = get_user_by_account(user['email'])
        if myuser is None:
            # 请求失败400, {"message": "对不起,用户不存在!"}字典 会返回给前端axios的catch
            return Response({"message": "用户邮箱不存在!"}, status=http_status.HTTP_400_BAD_REQUEST)

        # 3.校验验证码
        conn = get_redis_connection()
        redis_code = conn.get(myuser.email)  # 根据邮箱去获取验证码
        # print("redis_code=", redis_code)
        if not redis_code:
            return Response({"message": "验证码失效,请重新发送!"}, status=http_status.HTTP_400_BAD_REQUEST)
        redis_str_code = redis_code.decode('utf-8')

        if user['code'].strip() != redis_str_code:
            return Response({"message": "验证码错误!"}, status=http_status.HTTP_400_BAD_REQUEST)

        # 4.邮箱和验证码校验成功之后,返回token(用户自定义返回jwt,之前是自动返回的)
        payload = jwt_payload_handler(myuser)   # myuser是object对象
        token = jwt_encode_handler(payload)

        return Response({"message": "登录成功!", "username": myuser.username, "id": myuser.id, "token": token},
                        status=http_status.HTTP_200_OK)

手动生成jwt

Django REST framework JWT 扩展的说明文档中提供了手动签发JWT的方法

from rest_framework_jwt.settings import api_settings

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)

DRF+VUE实现密码与验证码登录_第21张图片测试一把:
DRF+VUE实现密码与验证码登录_第22张图片
DRF+VUE实现密码与验证码登录_第23张图片
ok啦

你可能感兴趣的:(vue.js,前端,javascript)