登录功能的实现(包括前后端)

Posted _Kiwi_Berry_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了登录功能的实现(包括前后端)相关的知识,希望对你有一定的参考价值。

目录:


🍉🍉🍉UPDATE:


突然发现喜提榜一,蟹蟹读者老爷们的支持(づ ̄ 3 ̄)づ

润色了一些格式,加了一些emjoi,还配上了一些颜色,希望能在枯燥的技术学习中多一些色彩捏。

(看了学弟的博客之后发现这样读下去的欲望会大大增加,于是就借鉴了一些hh,在这里强烈推荐一下他的博客:

★,°:.☆( ̄▽ ̄)/$:.°★

阳树阳树

是个很厉害,进步超快的博主呢!


✨✨✨前言

登录功能对于前端刚入门不久的我来说较为困难,花了很久查阅了许多资料。代码部分涉及的技术栈和细节也很多。
过了一段时间来看,发现对自己写的代码竟然感觉十分陌生,故想写篇博客,对整个过程进行梳理。方便自己重看代码,同时也希望能帮到在实现这一功能受阻的程序猿们o( ̄▽ ̄)ブ



✨✨✨概述


登录功能的实现大致可分成6步:

1.前端验证用户输入是否符合规范

2. 前端调用后端登录接口,向后端发起登录请求

3. 后端收到请求,查验数据库种是否有相应账号以及密码是否正确

4.验证通过后,将成功信息连同token一起发送给前端

5.前端将token储存起来,每次用户进入需要登录才能访问的页面时或者每次进入网站时向后端发送token

6. 若过期,则清除用户信息,回到未登录状态



✨✨✨技术栈

  • 前端:JavaScript,Vue

    • axios (发送请求的第三方库)

    • element-plus (基于 Vue 3 的组件库,简化UI代码)


  • 后端:Node.js

    • express (简化请求响应代码)
    • cors (解决跨域问题)
    • bcryptjs(密码加密解密)
    • jsonwebtoken(实现token的生成与验证)



✨✨✨效果图

登陆前


登录界面

登录成功




✨✨✨代码

表单验证及发送请求

<template>
  <el-form
    ref="ruleFormRef"
    :model="ruleForm"
    :rules="rules"
    label-width="35rem"
  >
    <el-form-item prop="phone_number" class="phone_number">
      <el-input
        type="text"
        placeholder="你的手机号/邮箱"
        v-model="ruleForm.phone_number"
      />
    </el-form-item>

    <el-form-item prop="password" class="password">
      <el-input
        type="password"
        placeholder="密码"
        v-model="ruleForm.password"
        autocomplete="off"
      />
    </el-form-item>

    <el-form-item class="login_in_button">
      <el-button type="primary" @click="submitForm(ruleFormRef)"
        >登录</el-button
      >
      <el-button>注册</el-button>
    </el-form-item>
  </el-form>
</template>

<script lang="ts" setup>
import  reactive, ref  from "vue";
import type  FormInstance  from "element-plus";
import  ElMessage  from "element-plus";
import  LoginInPost  from "../../api/LoginIn";
import  useRouter  from "vue-router";
import axios from "axios";
import  useStore  from "../../../store.js";
import  storeToRefs  from "pinia";

const router = useRouter();
const store = useStore();
// const  islogin  = storeToRefs(store);

const formSize = ref("default");
const ruleFormRef = ref<FormInstance>();
const ruleForm = reactive(
  phone_number: "",
  password: "",
);

const checkPhonenumber = (rule: any, value: string, callback: any) => 
  if (!value) 
    callback(new Error("请输入注册时用的邮箱或者手机号呀"));
  
  let re = /^[0-9]*$/;
  // console.log(value.length);
  // ||value.length != 11
  if (!re.test(value)) 
    // console.log(re.test(value));
    callback(new Error("输入格式有误哟"));
   else 
    callback();
  
;

const checkPassword = (rule: any, value: string, callback: any) => 
  if (!value) 
    return callback(new Error("请输入密码呀"));
  
  let re = /^[0-9a-zA-Z]*$/;

  if (!re.test(value)) 
    // console.log(re.test(value));
    return callback(new Error("输入格式有误哟"));
   else 
    return callback();
  
;

const rules = reactive(
  phone_number: [ validator: checkPhonenumber, trigger: "blur" ],
  password: [ validator: checkPassword, trigger: "blur" ],
);

const submitForm = async (formEl: FormInstance | undefined) => 
  if (!formEl) return;
  await formEl.validate((valid, fields) => 
    if (valid) 
      let url = "http://localhost:3007/api/user_register";
      let dataObject = reactive(
        phoneNumber: ruleForm.phone_number,
        password: ruleForm.password,
      );
      try 
        LoginInPost(dataObject).then(function (res) 
          // console.log(res.data.token);
          if (res.data.status == 0) 
            store.loginIn();
            localStorage.setItem("token",res.data.token);
            router.go(-1);
           else if (res.data.status == 403) 
            ElMessage( message: res.data.message, offset: 200 );
          
        );
       catch (error) 
        console.log(error);
      
     else 
      console.log("error submit!", fields);
    
  );
;
</script>

axios封装

index.js

import db from "../db/user_db.js"
import bcrypt from "bcryptjs"
import jwt from "jsonwebtoken"
import config from "../config.js"

export async function regUser(req, res) 
    try 
        // console.log(req.body);
        const data = req.body;
        // console.log(data.phoneNumber);
        const selectSql = "select * from users where phoneNumber=?";
        let [result] = await db.query(selectSql, data.phoneNumber)
            .catch(err =>  console.log(err) );
        // console.log(result.length);
        //号码已占用
        if (result.length > 0) 
            throw new Error(res.send(
                status: 403,
                message: "电话号码已注册过了嗷",
            ))
        

        //对密码进行加密
        // console.log(data.password);
        data.password = bcrypt.hashSync(data.password, 10);
        console.log(data.password);
        const insertSql = "insert into users set ?";

        const insertStr =  phoneNumber: data.phoneNumber, password: data.password ;
        [result] = await db.query(insertSql, insertStr)
            .catch(err =>  console.log(err) );
        // console.log(result.affectedRows);
        if (result.affectedRows != 1) 
            res.send(
                status: 403,
                message: "请求失败",
            )
        
        res.send(
            status: 0,
            message: "请求成功",
        )
     catch (err) 
        res.send(
            status: 403,
            message: "请求失败",
            desc: err.message
        )

    




export async function loginUser(req, res) 
    try 
        // console.log(req.body);
        const data = req.body;
        // console.log(data.phoneNumber);
        const selectSql = "select * from users where phoneNumber=?";
        let [result] = await db.query(selectSql, data.phoneNumber)
            .catch(err =>  console.log(err) );
        // console.log(result);
        //无注册账号
        if (result.length == 0) 
            return res.send(
                status: 403,
                message: "无注册账号",
            )
        

        //验证密码
        // console.log(result[0].password);
        const compareResult = bcrypt.compareSync(data.password, result[0].password);
        if (compareResult == 0) 
            return res.send(
                status: 403,
                message: "密码错误",
            )
        

        const user =  ...result[0], password: '' ;
        console.log(user);
        const tokenStr = jwt.sign(user, config.jwtSecretKey,  expiresIn: "10h" );
        return res.send(
            status: 0,
            message: "登录成功",
            token: tokenStr
        )
     catch (err) 
        return res.send(
            status: 403,
            message: "请求失败",
            desc: err.message
        )

    


export async function GetInfo(req, res) 
    console.log(req.headers.authorization);
    const token = req.headers.authorization;
    if (!token) 
        return res.send(
            status: 403,
            message: "无token"
        )
    
    try
        const flag = jwt.verify(token, config.jwtSecretKey);
        if (flag) 
            return res.send(
                status: 0,
                message: "验证成功"
            )
         else 
            return res.send(
                status: 403,
                message: "token错误"
            )
        
    catch(err)
        return res.send(
            status: 403,
            message: "token已过期"
        )
    
    



request.js

// http/axios.js
import instance from "./index"
/**
 * @param String method  请求的方法:get、post、delete、put
 * @param String url     请求的url:
 * @param Object data    请求的参数
 * @param Object config  请求的配置
 * @returns Promise     返回一个promise对象,其实就相当于axios请求数据的返回值
 */

export const axios = (
    method,
    url,
    data,
    config
) => 
    method = method.toLowerCase();
    if (method == 'post') 
        return instance.post(url, data, ...config)
     else if (method == 'get') 
        return instance.get(url, 
            params: data,
            ...config
        )
     else if (method == 'delete') 
        return instance.delete(url, 
            params: data,
            ...config
        , )
     else if (method == 'put') 
        return instance.put(url, data,...config)
     else 
        console.error('未知的method' + method)
        return false
    


Login.js

import  axios  from "../utils/request"

export const LoginInPost = (data) => 
    return axios(
        url: "http://localhost:3007/api/user_login",
        method: "post",
        data
    )


export const GetUsersInfo = (data) => 
    return axios(
        url: "http://localhost:3007/api/get_info",
        method: "get",
        data
    )

登录验证

export async function loginUser(req, res) 
    try 
        // console.log(req.body);
        const data = req.body;
        // console.log(data.phoneNumber);
        const selectSql = "select * from users where phoneNumber=?";
        let [result] = await db.query(selectSql, data.phoneNumber)
            .catch(err =>  console.log(err) );
        // console.log(result);
        //无注册账号
        if (result.length == 0) 
            return res.send(
                status: 403,
                message: "无注册账号",
            )
        

        //验证密码
        // console.log(result[0].password);
        const compareResult = bcrypt.compareSync(data.password, result[0].password);
        if (compareResult == 0) 
            return res.send(
                status: 403,
                message: "密码错误",
            )
        

        const user =  ...result[0], password: '' ;
        console.log(user);
        const tokenStr = jwt.sign(user, config.jwtSecretKey,  expiresIn: "10h" );
        return res.send(
            status: 0,
            message: "登录成功",
            token: tokenStr
        )
     catch (err) 
        return res.send(
            status: 403,
            message: "请求失败",
            desc: err.message
        )

    



✨✨✨github链接

想要看完整版代码以及页面效果,请移步github哦
https://github.com/Ki-Wi-Berry/bilibili-videos


⛄码字不易,如果觉得对您有帮助的话,麻烦点个免费的赞~⛄

以上是关于登录功能的实现(包括前后端)的主要内容,如果未能解决你的问题,请参考以下文章

SpringSecurity实现前后端分离项目的登录认证

SpringBootSecurity学习(12)前后端分离版之简单登录

前后端渲染

千呼万唤,web人脸识别登录完整版来了,这样式我爱了

千呼万唤,web人脸识别登录完整版来了,这样式我爱了

springboot集成Thymeleaf实现一个用户的增删改查功能,包括前后端代码实现