后台管理员登录实现--系统篇

        我的小系统后台原来就有一个上传图片的功能还夹带个删除图片的功能,还嵌到了一个菜单里面。之前效果如下

        那么现在为了加大安全力度,想增加一个登录页面。通过登录再到这个页面。看着貌似很简单,但是听我细细说来,要新增些什么东西才能做到增加一个登录页面。

        可以先从前端代码入手,也可以从后端代码入手,这边先从前端代码入手,先做出个感性认知,效果如下

        这里选择用Form表单来实现,代码如下

<el-form :model="form" style="max-width: 600px" label-width="60px" label-position="left">
          <el-form-item label="用户名">
            <el-input v-model="form.name" />
          </el-form-item>
          <el-form-item label="密码">
            <el-input v-model="form.password" type="password" />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="onSubmit">登录</el-button>
          </el-form-item>
        </el-form>

        细看代码,总共摆放了2个输入框和对应的文字提示以及一个登录按钮。label部分宽度调到了60px,label-width="60px"。label位置调成左对齐,label-position="left"。密码输入框设置成密文模式type="password"

        然后要设置成差不多居中显示和弄一个开关来控制是否渲染这个登录页面,因为之前就说了还有另外一些页面要衔接起来。做法还可以由后端来提供路由控制,就是后端来提供登录页面的路由和登录后主体页面的路由。但是如果是这么做就有很多麻烦的事情,比如打包的时候要打包2份给后端,还要弄2个前端入口,调试不方便等等。

        <div v-if="exist.login_exist === false">
        <router-view></router-view>
    </div>
    <div class="container" v-else>

把上面的表单放到这里

    </div>

        exist.login_exist,这个就是页面开关,为false的时候就显示登录页面,登录成功后可以设置为true,至于差不多居中显示代码如下

#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

.container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 70vh; /* 使用视窗高度来使容器撑满整个屏幕 */
}

        #app的样式是默认的,我没改过,主要看.container样式

        接下来看看这个入口页面的逻辑实现,没改的话就是App.vue

const router = useRouter()

// do not use same name with ref
const form = reactive({
  name: '',
  password:'',
})

const exist = reactive({login_exist:true})

const onSubmit = () => {
  
  axios.post('http://admin.am8.com/anonym/login', {
      name: form.name,
      password: form.password
    })
    .then(function (response) {

      if (response.data.code === 1) {
          store.setToken(response.data.data)
          exist.login_exist = false
          router.push({path:'/sidebar'})
      } else {
          ElMessage.warning(response.data.msg)
      }
    })
    .catch(function (error) {
      console.log(error);
    });

}

        前面那3个定义分别是定义路由,定义form表单数据对象,定义页面开关

const router = useRouter()

// do not use same name with ref
const form = reactive({
  name: '',
  password:'',
})

const exist = reactive({login_exist:true})

        最后就是登录方法onSubmit的实现,向后端请求登录,注意看登录成功后做的事情

 if (response.data.code === 1) {
          store.setToken(response.data.data)
          exist.login_exist = false
          router.push({path:'/sidebar'})
      }

        存储登录令牌

store.setToken(response.data.data)

        页面开关设置为false

exist.login_exist = false

        跳转到/sidebar

router.push({path:'/sidebar'})

        看不懂/sidebar?那就先看看前端路由部分

import { createRouter, createWebHistory } from 'vue-router'
import Upload1 from './views/Upload1.vue'
import Sidebar from './views/menu/Sidebar.vue'
import App from './App.vue'

export const router = createRouter({
  history: createWebHistory(),
  routes: [
      { path: '/', component: App },
      { path: '/sidebar', component: Sidebar, children: [
          {
          
            path: '',
            component: Upload1,
          },
          {

            path: 'addImage',
            component: Upload1,
          },
        ], },
    ]
})
        看出来了吧,/sidebar是Sidebar.vue这个页面,Sidebar.vue页面仅仅是个我之前写的Menu菜单页面,Menu菜单里面的

        接下来看看后端的实现,数据库基于mysql5.7。先建立2张数据表,一张管理员表

CREATE TABLE `am8_admin` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  `password` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

        一张管理员登录令牌表

CREATE TABLE `am8_admin_token` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `admin_id` int(11) NOT NULL,
  `token` varchar(100) NOT NULL COMMENT '登录令牌',
  `client` tinyint(3) NOT NULL COMMENT '登录渠道。1.PC,2.H5',
  `create_time` int(11) NOT NULL COMMENT '首次登录时间戳',
  `update_time` int(11) NOT NULL COMMENT '最后一次登录时间戳',
  `ip` varchar(30) NOT NULL COMMENT '登录地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

        后端框架基于thinkphp8,然后新建2个模型类,Admin和AdminToken。新建Anonym控制器,将BaseController复制一份到Admin应用下

        BaseController修改如下

protected function initialize()
    {
        $exist = AdminToken::where([
            'token' => request()->param('token'),
        ])->find();

        if ($exist !== null) {
            // 获取当前时间的时间戳
            $now = time();
            
            $timestamp = intval($exist->update_time);
            
            // 设定1小时的秒数
            $oneHourInSeconds = 3600;
            
            if (($now - $timestamp) > $oneHourInSeconds) {
                return myFailResponse(0, '登录状态已过期');
            }
        } else {
            return myFailResponse(0, '未登录');
        }
    }

        这里实现的是登录状态检查,后面所有需要登录才实现的功能都要继承这个类

        Anonym这个类里面实现了登录的接口,这个类就不用继承BaseController

public function login()
    {
        $admin = new Admin();
        
        $exist = $admin->where([
            'name' => request()->param('name'),
            'password' => $this->encrypt(request()->param('password')),
        ])->find();
        if ($exist !== null) {
            $result = $this->loginStateHandler($exist['id']);
            return mySuccessResponse($result);
        } else {
            return myFailResponse(1, '用户名或密码有误');
        }
        
    }

        encrypt这个是密码的加密方法,这里就不展示了,我也没想好怎么写,只是随手实现了加密。有的人想用hash就用hash,有的人想加盐就加盐,这里不展开了。

        loginStateHandler这个方法是对登录状态做处理。

private function loginStateHandler($id)
    {
        $exist = AdminToken::where([
            'admin_id' => $id,
            'client' => 1
        ])->find();
        
        // 获取当前时间的时间戳
        $now = time();
        
        if ($exist !== null) {
            $timestamp = intval($exist->update_time);
            
            // 设定1小时的秒数
            $oneHourInSeconds = 3600;
            
            if (($now - $timestamp) > $oneHourInSeconds) {
                $token = $this->createToken($id, $now);
                $exist->token = $token;
                $exist->ip = $this->getClientIp();
                $exist->save();
                
                return $token;
            } else {
                $exist->ip = $this->getClientIp();
                $exist->save();
                return $exist['token'];
            }
        } else {
            $admin_token = new AdminToken();
            $token = $this->createToken($id, $now);
            $admin_token->admin_id = $id;
            $admin_token->token = $token;
            $admin_token->client = 1;
            $admin_token->ip = $this->getClientIp();
            $admin_token->save();
            
            return $token;
        }
        
    }

        createToken方法是生成登录令牌的方法,这里就不展开了,因为我没想好,只是随手实现了一下,getClientIp这个是获取客户端ip的方法,也是没想好怎么写,不展开了,随手实现了一个。

        另外还要注意修改配置database.php,datetime_format的值改为false,避免取出时间戳时会被格式化从而导致登录逻辑出错

        既然后端已经支持登录验证,那么前面写的上传图片和删除图片的前端部分也要作出修改,提供相应支持,其实就是增加发送参数token,Upload1.vue文件修改如下

        <el-upload
      v-model:file-list="fileList"
      class="upload-demo"
      action="http://admin.am8.com/index/upload"
      :data="{token:store.token}"
      name="image"
      list-type="picture"
      :on-success="handleSuccess"
      :on-preview="handlePreview"
      :on-remove="handleRemove"
      :before-remove="beforeRemove"
      :limit="3"
      :on-exceed="handleExceed"
    >

        上传组件增加:data,除了发送上传图片外,多发送个token。

const handleSuccess: UploadProps['onSuccess'] = (response, uploadFile, uploadFiles) => {
  if (response.code === 1) {
      fileList.value.pop()
      fileList.value.push(response.data)
  } else {
      if (response.code === 0) {
        fileList.value.pop()
          ElMessage.warning(response.msg)
      }
  }
  
}

        成功上传后,增加根据后端返回登录状态的提示

const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {

  axios.post('http://admin.am8.com/index/deleteFile', {
      token: store.token,
      id: file.id,
    })
    .then(function (response) {
      if (response.data.code === 1) {
          
      } else {
          if (response.data.sub_code === 0) {
              router.push({path:'/'})
          }

      }
    })
    .catch(function (error) {
      console.log(error);
    });
}

        删除图片时也要增加发送token参数,还有登录状态不存在或者失效时跳转回登录页面,前后展示了2种失败后处理做法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/57733.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#第四讲:C#语言基本元素概览,初识类型、变量与方法,算法简介

一、构成C#语言的基本元素 1、标识符 允许将下划线用作初始字符(这是C编程语言的传统)。 允许在标识符中使用 Unicode 转义序列&#xff0c;以及允许“”字符作为前缀以使关键字能够用作标识符。 &#xff08;1&#xff09;命名方法 变量名&#xff1a;用驼峰法。&#xff…

【SQL实验】表的更新和简单查询

完整代码在文章末尾 在上次实验创建的educ数据库基础上&#xff0c;用SQL语句为student表、course表和sc表中添加以下记录 【SQL实验】数据库、表、模式的SQL语句操作_创建一个名为educ数据库,要求如下: (下面三个表中属性的数据类型需要自己设计合适-CSDN博客在这篇博文中已经…

安全见闻---清风

注&#xff1a;本文章源于泷羽SEC&#xff0c;如有侵权请联系我&#xff0c;违规必删 学习请认准泷羽SEC学习视频:https://space.bilibili.com/350329294 安全见闻1 泷哥语录&#xff1a;安全领域什么都有&#xff0c;不要被表象所迷惑&#xff0c;无论技术也好还是其他方面…

[jeecg-boot] vue3 版本 nvm 下载node版本

安装pnpm 使用cnpm 进行下载依赖

JavaWeb 23.一文速通npm的配置和使用

目录 一、npm的介绍 二、npm的安装和配置 1.安装 &#xff1a; 2.配置依赖下载使用阿里镜像 3. 配置全局依赖下载后存储位置 4.升级npm版本 5.环境变量配置 三、npm常用命令 1.项目初始化 npm.init npm init -y 2.安装依赖文件 3. 升级依赖 4.卸载依赖 5.查看依赖 查看项目…

深入浅出 Vue3 nextTick

程序员节日快乐~ #1024程序员节 | 征文# nextTick 概念 当你在 Vue 的响应式数据模型中对数据进行修改时&#xff0c;这些变化并不会立即同步到 DOM 上_&#xff0c;而是会在当前的微任务队列&#xff08;microtask queue&#xff09;执行完毕后进行批量更新。这种机制被称为…

内网穿透:如何借助Cloudflare连接没有公网的电脑的远程桌面(RDP)

内网穿透&#xff1a;如何借助Cloudflare连接没有公网的电脑的远程桌面(RDP)-含详细原理配置说明介绍 前言 远程桌面协议(RDP, Remote Desktop Protocol)可用于远程桌面连接&#xff0c;Windows系统&#xff08;家庭版除外&#xff09;也是支持这种协议的&#xff0c;无需安装…

使用 NumPy 和 Matplotlib 实现交互式数据可视化

使用 NumPy 和 Matplotlib 实现交互式数据可视化 在数据分析中&#xff0c;交互式可视化可以更好地帮助我们探索和理解数据。虽然 Matplotlib 是静态绘图库&#xff0c;但结合一些技巧和 Matplotlib 的交互功能&#xff08;widgets、event handlers&#xff09;&#xff0c;我…

水轮发电机油压自动化控制系统解决方案介绍

在现代水电工程中&#xff0c;水轮机组油压自动化控制系统&#xff0c;不仅直接关系到水轮发电机组的安全稳定运行&#xff0c;还影响着整个水电站的生产效率和经济效益。 一、系统概述 国科JSF油压自动控制系统&#xff0c;适用于水轮发电机组调速器油压及主阀&#xff08;蝶…

Dongle Sentinal在Jenkins下访问不了的问题

背景&#xff1a; 工作站部署的jenkins的脚本无法正常打包&#xff0c;定位后发现是本地获取不了license&#xff0c;但是使用usb over network的远程license都能获取并正常打包 分析&#xff1a; 获取不了license的原因是本地无法识别dongle。根据提供信息&#xff0c;之前…

SAP_SD模块-销售订单创建价格扩大10倍问题分析及后续订单价格批量更新问题处理

一、业务背景 我们公司的销售订单&#xff0c;是通过第三方销售管理平台创建好订单后&#xff0c;把表头和行项目数据&#xff0c;定时推送到SAP&#xff1b;SAP通过自定义表ZZT_ORDER_HEAD存放订单表头数据&#xff0c;通过ZZT_ORDER_DETAIL存放行项目数据&#xff1b;然后再用…

探索AI人工智能机器学习:解锁未来科技的钥匙

作者简介&#xff1a;我是团团儿&#xff0c;是一名专注于云计算领域的专业创作者&#xff0c;感谢大家的关注 座右铭&#xff1a; 云端筑梦&#xff0c;数据为翼&#xff0c;探索无限可能&#xff0c;引领云计算新纪元 个人主页&#xff1a;团儿.-CSDN博客 前言&#xff1a;…

【C#】使用Visual Studio创建Windows Forms应用程序计算对角线之和

文章目录 使用Visual Studio创建Windows Forms应用程序计算对角线之和步骤 1: 创建新的Windows Forms应用程序项目步骤 2: 设计窗体步骤 3: 编写代码步骤 4: 运行程序步骤 5: 运行结果 使用Visual Studio创建Windows Forms应用程序计算对角线之和 大家好&#xff01;今天&…

Spring Boot:植物健康的智能守护者

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

【网络原理】TCP/IP五层网络模型之网络层-----IP协议详解,建议收藏!!

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;计算机网络那些事 前几篇文章中我们深入研究了TCP协议&#xff0c;因为TCP协议在我们日常开发中的使用频率非常高。而相比之下&#xff0c;IP协议与我们普通程序员关系就没那么近了。一般是专门开发…

数字 图像处理算法的形式

一 基本功能形式 按图像处理的输出形式&#xff0c;图像处理的基本功能可分为三种形式。 1&#xff09;单幅图像 单幅图像 2&#xff09;多幅图像 单幅图像 3&#xff09;单&#xff08;或多&#xff09;幅图像 数字或符号等 二 几种具体算法形式 1.局部处理邻域对于任一…

libevent源码剖析-event

1 简介 本文来重点介绍下libevent中的event事件&#xff0c;在类unix系统中编写网络程序时&#xff0c;我们经常需要处理3类事件-IO事件&signal事件&timer事件&#xff0c;libevent通过reactor来注册&调度&处理IO事件&#xff0c;并且也将signal和timer事件借助…

2024年10月21日计算机网络,乌蒙第一部分

【互联网数据传输原理 &#xff5c;OSI七层网络参考模型】 https://www.bilibili.com/video/BV1EU4y1v7ju/?share_sourcecopy_web&vd_source476fcb3b552dae37b7e82015a682a972 mac地址相当于是名字&#xff0c;ip地址相当于是住址&#xff0c;端口相当于是发送的东西拿什…

SPI通信(W25Q64)

目录 一.前言 1.SPI的简介 2.SPI的应用 3. SPI的硬件电路 4. SPI硬件电路设计的核心 5. SPI时序基本单元 二. W25Q64简介 1. 芯片简介 2. &#xff08;非&#xff09;易失性存储器 3. 引脚定义 4. W25Q64框图 5. Flash操作的注意事项 三. SPI读写W25Q64&#xff08;使用软件…

一文教会你如何使用 iLogtail SPL 处理日志

作者&#xff1a;阿柄 随着流式处理的发展&#xff0c;出现了越来越多的工具和语言&#xff0c;使得数据处理变得更加高效、灵活和易用。在此背景下&#xff0c;SLS 推出了 SPL(SLS Processing Language) 语法&#xff0c;以此统一查询、端上处理、数据加工等的语法&#xff0…