当前位置: 首页 > news >正文

服务端开发模式-thinkphp-重新整理workman

一、登录接口

<?php
/*** 登录退出操作* User: 龙哥·三年风水* Date: 2024/10/29* Time: 15:53*/
namespace app\controller\common;
use app\controller\Emptys;
use app\model\permission\Admin;
use app\model\param\System as SystemModel;
use Email\EmailSender;
use Other\Browser;
use Redis\Redis;
use app\model\common\Token as TokenModel;
use Encipher\Encrypt;
use Workman\GatewayWork;class Login extends Emptys
{//验证码展示public function getCode(){$re = app()->make(\Other\Captcha::class)->create();$base64 = 'data:image/png;base64,' . base64_encode($re->getData());return succ('SUCCESS',$base64);}//登录public function doLogin(){$param = $this->request->param();$validate = new \app\validate\common\Login;$result = $validate->check($param);//参数验证if (!$result) return err($validate->getError());//验证码的正确性if (!app()->make(\Other\Captcha::class)->check($param['captcha_code'])) return err('验证码错误');//if (time() + 5 < strtotime($param['login_time'])) return err('非法登录');$resData = Admin::dataFind(['email' => trim($param['username'])], 'id,realname,password,ip,status', true);//用户信息的正确性if (empty($resData) && empty($resData['id'])) return err('用户不存在');if ($resData['status'] !== 1) return err('该账号已被禁用');$systemParam = SystemModel::dataFind(['id' => 1],'security_password,platform_token_expira');if ($resData['password'] !== sha1($param['password'] . $systemParam['security_password'])) return err('账号对应的密码错误');$loginIp = $this->request->header('x-real-ip');if(!empty($resData['ip'])){if($resData['ip'] != $loginIp)return err('禁止访问,不在IP白名单中');}// 获取浏览器版本$browserId = Browser::getVersion();// 获取该用户是否在登录状态下$tokenId = Redis::select(config('cache.stores.redis.token_db'))->get('token_' . $resData['id']);// 如果在登录状态下,需要确认IP是否一致if(!empty($tokenId)){$tokenValue = explode('|', Encrypt::decryptRsa($tokenId));//解密 --转换tokenif(count($tokenValue) > 0){$tokenSelect = count($tokenValue) == 2 ? sha1(sha1($tokenValue[0]).strtotime($tokenValue[1])) : $tokenValue[0];// 读取用户之前登录的IP及浏览器$resTokenLogin = TokenModel::dataFind(['token' => $tokenSelect,'token_type' => 1],'id,random_number,browser_id,login_ip',true);// 如果之前登录的IP存在 之前登录的IP与现在登录的IP进行对比if(!empty($resTokenLogin)){// 如果不相等的情况下,需要告知之前的浏览器做退出动作if($loginIp != $resTokenLogin['login_ip']){TokenModel::save(['expire_time' => time()], ['token' => $tokenSelect]);$this->setToken(3,'PermissionMemberLogout',$resData['id'],$resTokenLogin['random_number'],$resTokenLogin['browser_id'],$resTokenLogin['login_ip'],$tokenSelect);Redis::select(config('cache.stores.redis.token_db'))->del('token_' . $tokenSelect);GatewayWork::onRepeatClose($resData['id']);}else{// 如果相等的情况下,就需要判断浏览器是否相等啦,如果不相等的情况下,也是需要让之前的账号多退出的动作if($browserId == $resTokenLogin['browser_id'])return err('已登录,不可再次登录');if($browserId != $resTokenLogin['browser_id']){TokenModel::save(['expire_time' => time()], ['token' => $tokenSelect]);$this->setToken(3,'PermissionMemberLogout',$resData['id'],$resTokenLogin['random_number'],$resTokenLogin['browser_id'],$resTokenLogin['login_ip'],$tokenSelect);Redis::select(config('cache.stores.redis.token_db'))->del('token_' . $tokenSelect);GatewayWork::onRepeatClose($resData['id']);}}}}}//写入Token日志$dataRandomNumber = alnum();$expireTime = strtotime($param['login_time']) + $systemParam['platform_token_expira'];$token = $resData['id'].$dataRandomNumber;$dataToken = sha1( sha1($token). strtotime($param['login_time']));$this->setToken(1,'CommonLoginDoLogin',$resData['id'],$dataRandomNumber,$browserId,$loginIp,$dataToken,$expireTime);//加入跨站攻击验证队列Redis::select(config('cache.stores.redis.token_db'))->setex('token_' . $dataToken,$systemParam['platform_token_expira'],$resData['id']);Redis::select(config('cache.stores.redis.token_db'))->setex('token_' . $resData['id'],$systemParam['platform_token_expira'],Encrypt::encryptRsa($dataToken));/*$emailSender = new EmailSender();$emailSender::send($param['username'],'登录系统',$resData['realname'].'于'.$param['login_time'].'登录系统');*/return succ('登录成功',Encrypt::encryptRsa($token));}/*** 操作日志记录* User: 龙哥·三年风水* Date: 2024/12/12* Time: 17:11* @ param $tokenType 操作类型* @ param $menuName 权限名称*/private function setToken($tokenType,$menuName,$adminId,$randomNumber,$browserId,$loginIp,$token,$expireTime = ''){$data['token_type'] = $tokenType;$data['menu_name'] = $menuName;$data['admin_id'] = $adminId;$data['random_number'] = $randomNumber;$data['browser_id'] = $browserId;$data['login_ip'] = $loginIp;$data['create_time'] = date('Y-m-d',time());$data['login_time'] = date('Y-m-d H:i:s',time());$data['expire_time'] = empty($expireTime) ? time() : $expireTime;$data['token'] = $token;TokenModel::save($data,[]);}
}

二、长链接封装

<?php
/*** 长链接发送信息* User: 龙哥 三年风水* Date: 2024/12/21/0021* Time: 22:52*/
namespace Workman;
use GatewayClient\Gateway;
class GatewayWork
{//向客户端发送内容public static function sendToClient($client_id, $data){//获取配置文件$isFormal = config('socket.is_formal');Gateway::$registerAddress = config("socket.tcp_address.{$isFormal}.address");Gateway::sendToClient($client_id, $data);}//向群推送数据public static function sendToGroup($group,$message){//获取配置文件$isFormal = config('socket.is_formal');Gateway::$registerAddress = config("socket.tcp_address.{$isFormal}.address");Gateway::sendToGroup($group,json_encode($message));}//批量向客户端发送内容public static function sendToAll($message, $client_id_array = null){//获取配置文件$isFormal = config('socket.is_formal');Gateway::$registerAddress = config("socket.tcp_address.{$isFormal}.address");Gateway::sendToAll(json_encode($message), $client_id_array);}//获取与 uid 绑定的 client_id 列表public static function getClientIdByUid($uid){//获取配置文件$isFormal = config('socket.is_formal');Gateway::$registerAddress = config("socket.tcp_address.{$isFormal}.address");return Gateway::getClientIdByUid($uid);}//重复登录关闭客户端public static function onRepeatClose($userId){//获取配置文件$isFormal = config('socket.is_formal');Gateway::$registerAddress = config("socket.tcp_address.{$isFormal}.address");$resUser = Gateway::isUidOnline((int)$userId);if($resUser == 1){$resClientUser = Gateway::getClientIdByUid((int)$userId);foreach ($resClientUser as $v){Gateway::sendToClient($v, json_encode(['type' => 'repeat_close','data' => 'ok']));Gateway::destoryClient($v);}}}//正常退出关闭客户端public static function onArtificialClose($userId){//获取配置文件$isFormal = config('socket.is_formal');Gateway::$registerAddress = config("socket.tcp_address.{$isFormal}.address");$resUser = Gateway::isUidOnline((int)$userId);if($resUser == 1){$resClientUser = Gateway::getClientIdByUid((int)$userId);foreach ($resClientUser as $v){Gateway::sendToClient($v, json_encode(['type' => 'artificial_close','data' => 'ok']));Gateway::destoryClient($v);}}}//到期退出关闭客户端public static function onExpireClose($userId){//获取配置文件$isFormal = config('socket.is_formal');Gateway::$registerAddress = config("socket.tcp_address.{$isFormal}.address");$resUser = Gateway::isUidOnline((int)$userId);if($resUser == 1){$resClientUser = Gateway::getClientIdByUid((int)$userId);foreach ($resClientUser as $v){Gateway::sendToClient($v, json_encode(['type' => 'expire_close','data' => 'ok']));Gateway::destoryClient($v);}}}
}

三、提前说明

        因最近一段时间比较忙,导致精力不能集中。之前封装的vue-element-admin与thinkphp6追加长链接workman项目开发文档中有些问题。所以今天与明后天彻底解决一下这个问题。请谅解。

相关文章:

服务端开发模式-thinkphp-重新整理workman

一、登录接口 <?php /*** 登录退出操作* User: 龙哥三年风水* Date: 2024/10/29* Time: 15:53*/ namespace app\controller\common; use app\controller\Emptys; use app\model\permission\Admin; use app\model\param\System as SystemModel; use Email\EmailSender; use…...

HTB:Access[WriteUP]

目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 将靶机TCP开放端口号提取并保存 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 尝试匿名连接至…...

【论文笔记】SmileSplat:稀疏视角+pose-free+泛化

还是一篇基于dust3r的稀疏视角重建工作&#xff0c;作者联合优化了相机内外参与GS模型&#xff0c;实验结果表明优于noposplat。 abstract 在本文中&#xff0c;提出了一种新颖的可泛化高斯方法 SmileSplat&#xff0c;可以对无约束&#xff08;未标定相机的&#xff09;稀疏多…...

电机控制的数字化升级:基于DSP和FPGA的仿真与实现

数字信号处理器&#xff08;DSP&#xff0c;Digital Signal Processor&#xff09;在工业自动化领域的应用日益广泛。DSP是一种专门用于将模拟信号转换成数字信号并进行处理的技术&#xff0c;能够实现信号的数字滤波、重构、调制和解调等多项功能&#xff0c;确保信号处理的精…...

1/14 C++

练习&#xff1a;将图形类的获取周长和获取面积函数设置成虚函数&#xff0c;完成多态 再定义一个全局函数&#xff0c;能够在该函数中实现&#xff1a;无论传递任何图形&#xff0c;都可以输出传递的图形的周长和面积 #include <iostream>using namespace std; class Sh…...

java springboot3.x jwt+spring security6.x实现用户登录认证

springboot3.x jwtspring security6.x实现用户登录认证 什么是JWT JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它用于在网络应用环境中传递声明。通常&#xff0c;JWT用于身份验证和信息交换。JWT的一个典型用法是…...

YOLOv5训练长方形图像详解

文章目录 YOLOv5训练长方形图像详解一、引言二、数据集准备1、创建文件夹结构2、标注图像3、生成标注文件 三、配置文件1、创建数据集配置文件2、选择模型配置文件 四、训练模型1、修改训练参数2、开始训练 五、使用示例1、测试模型2、评估模型 六、总结 YOLOv5训练长方形图像详…...

【2025最新】Poe保姆级订阅指南,Poe订阅看这一篇就够了!最方便使用各类AI!

1.Poe是什么&#xff1f; Poe, 全称Platform for Open Exploration。 Poe本身并不提供基础的大语言模型&#xff0c;而是整合多个来自不同科技巨头的基于不同模型的AI聊天机器人&#xff0c;其中包括来自OpenAI的ChatGPT&#xff0c;Anthropic的Claude、Google的PaLM&#xf…...

type1-100,2 words

dish n.餐具、碟&#xff0c;盘子&#xff1b;菜肴、饭菜&#xff08;指一顿餐食中的一道菜&#xff09; kind of 稍微&#xff1b;有点 sort of 稍微&#xff1b;有点儿 smallish adj.有点小的 crack 敲碎/裂&#xff0c;敲开&#xff0c;砸开&#xff0c;砸碎&#xff1b;裂开…...

Leetcode 377. 组合总和 Ⅳ 动态规划

原题链接&#xff1a;Leetcode 377. 组合总和 Ⅳ 可参考官解 class Solution { public:int combinationSum4(vector<int>& nums, int target) {vector<int> dp(target 1);dp[0] 1;// 总和为 i 的元素组合的个数for (int i 1; i < target; i) {// 每次都…...

计算机网络(五)——传输层

一、功能 传输层的主要功能是向两台主机进程之间的通信提供通用的数据传输服务。功能包括实现端到端的通信、多路复用和多路分用、差错控制、流量控制等。 复用&#xff1a;多个应用进程可以通过同一个传输层发送数据。 分用&#xff1a;传输层在接收数据后可以将这些数据正确分…...

【SQL】进阶知识 -- 删除表的几种方法(包含表内单个字段的删除方法)

大家好&#xff01;欢迎来到本篇SQL进阶博客。如果你已经掌握了基础的SQL操作&#xff0c;接下来就让我们一起探索删除表的几种方法。删除表可能听起来有点危险&#xff0c;事实也是如此&#xff0c;所以在我们实际开发过程中&#xff0c;大多数时候我们都有数据的使用权限&…...

【搭建JavaEE】(3)前后端交互,请求响应机制,JDBC数据库连接

前后端交互 Apache Tomat B/S目前主流。 tomat包含2部分&#xff1a; apache容器 再认识servlet 抽象出的开发模式 项目创建配置 maven javaeetomcat 忽略一些不用的文件 webapp文件夹 HiServlet 这里面出现了webinfo&#xff0c;这个别删因为这个呢&#xff0c;是这这个这…...

项目概述、开发环境搭建(day01)

软件开发整体介绍 软件开发流程 第1阶段: 需求分析 需求规格说明书&#xff0c; 一般来说就是使用 Word 文档来描述当前项目的各个组成部分&#xff0c;如&#xff1a;系统定义、应用环境、功能规格、性能需求等&#xff0c;都会在文档中描述。产品原型&#xff0c;一般是通过…...

车联网安全--TLS握手过程详解

目录 1. TLS协议概述 2. 为什么要握手 2.1 Hello 2.2 协商 2.3 同意 3.总共握了几次手&#xff1f; 1. TLS协议概述 车内各ECU间基于CAN的安全通讯--SecOC&#xff0c;想必现目前多数通信工程师们都已经搞的差不多了&#xff08;不要再问FvM了&#xff09;&#xff1b;…...

【python】OpenCV—Extract Horizontal and Vertical Lines—Morphology

文章目录 1、功能描述2、代码实现3、效果展示4、完整代码5、参考 更多有趣的代码示例&#xff0c;可参考【Programming】 1、功能描述 基于 opencv-python 库&#xff0c;利用形态学的腐蚀和膨胀&#xff0c;提取图片中的水平或者竖直线条 2、代码实现 导入基本的库函数 im…...

Redis十大数据类型详解

Redis&#xff08;一&#xff09; 十大数据类型 redis字符串&#xff08;String&#xff09; string是redis最基本的类型&#xff0c;一个key对应一个value string类型是二进制安全的&#xff0c;意思是redis的string可以包含任何数据。例如说是jpg图片或者序列化对象 一个re…...

Open FPV VTX开源之betaflight配置

Open FPV VTX开源之betaflight配置 1. 源由2. 配置3. 总结4. 参考资料5. 补充 - 飞控固件版本 1. 源由 飞控嵌入式OSD - ardupilot配置使用betaflight配套OSD图片。 Choose correct font depending on Flight Controller SW. ──> /usr/share/fonts/├──> font_btfl…...

AT32 bootloader程序与上位机程序

从8051到stm32, 从串口下载到JLINK调试&#xff0c;从keil到arm-none-eabi-gcc,从"Hello wrold"到通信协议&#xff0c;一路起来已学会很多&#xff0c;是时候写一下bootloader了。 基本原理 单片机代码编译完后可以生成".hex"和".bin"文件&…...

数据结构与算法之栈: LeetCode 151. 反转字符串中的单词 (Ts版)

反转字符串中的单词 https://leetcode.cn/problems/reverse-words-in-a-string/ 描述 给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开 返回 单词 顺序颠倒且 单词 之间用单个空…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...