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

lnmp - 登录技术方案设计与实现

概述

登录功能是对于每个动态系统来说都是非常基础的功能,用以区别用户身份、和对应的权限和信息,设计出一套安全的登录方案尤为重要,接下来我介绍一下常见的认证机制的登录设计方案。

方案设计

HTTP 是一种无状态的协议,客户端每次发送请求时,首先要和服务器端建立一个连接,在请求完成后又会断开这个连接。系统登录的本质是确认用户的合法性和身份

Cookie + Session 登录

在 B/S 系统中,登录功能通常都是基于 Cookie 来实现的。当用户登录成功后,一般会将登录状态记录到 Session 中。要实现服务端对客户端的登录信息进行验证都,需要在客户端保存一些信息(SessionId),并要求客户端在之后的每次请求中携带它们。在这样的场景下,使用 Cookie 无疑是最方便的,因此我们一般都会将 Session 的 Id 保存到 Cookie 中,当服务端收到请求后,通过验证 Cookie 中的信息来判断用户是否登录 。

用户首次登录流程

在这里插入图片描述

1、用户访问 www.stark.com/login,并输入密码登录。
2、服务器验证密码无误后,会创建 SessionId,并将它保存起来。
3、服务器端响应这个 HTTP 请求,并通过 Set-Cookie 头信息,将 SessionId 写入 Cookie 中。

cookice后续校验流程

获取cookice后续的访问就可以直接使用 Cookie 进行身份验证了

在这里插入图片描述

1、用户访问 www.stark.com/console 页面时,会自动带上第一次登录时写入的 Cookie
2、服务器端比对 Cookie 中的 SessionId 和保存在服务器端的 SessionId 是否一致。
3、如果一致,则身份验证成功,访问页面;如果无效,则需要用户重新登录。

需要注意的是: Cookie + Session 的方案中最关键的环节是传递Cookie有时可能会面临Cookie禁用的情况,记住只要把Cookie的值传递给服务端得到SessionId即可,可以是存储在LocalStorage,也可以使用URL 的GET方式传输。

Cookie + Session 技术实现

Cookie + Session的核心点在于数据的加密和解密的算法,在用户登录进行加密、生成Cookie,在之后的交互的时候携带在header的信息头中。

加密函数代码:

function passportEncrypt($txt, $key = 'stark-server@2024@#$!'): string
{$txt = 'yy-依加衣-' . time() . '-' . $txt;srand((double)microtime() * 1000000);$encrypt_key = md5(rand(0, 32000));// 变量初始化$ctr = 0;$tmp = '';for ($i = 0; $i < strlen($txt); $i++) {$ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;$tmp .= $encrypt_key[$ctr] . ($txt[$i] ^ $encrypt_key[$ctr++]);}return base64_encode(passportKey($tmp, $key));
}function passportKey($txt, $encrypt_key): string
{$encrypt_key = md5($encrypt_key);$ctr = 0;$tmp = '';for ($i = 0; $i < strlen($txt); $i++) {$ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;$tmp .= $txt[$i] ^ $encrypt_key[$ctr++];}return $tmp;
}

字符串解密函数:


function passportDecrypt($txt, $key = 'stark-server@2024@#$!')
{$txt = str_replace(' ', '+', $txt);$txt = passportKey(base64_decode($txt), $key);$tmp = '';for ($i = 0; $i < strlen($txt); $i++) {if (!isset($txt[$i]) || !isset($txt[$i + 1])) {return 0;} else {$tmp .= $txt[$i] ^ $txt[++$i];}}$tmp = explode('-', $tmp);$tmp[3] = $tmp[3] ?? 0;return $tmp[3];
}

加密解密实现的具体逻辑:

//加密
$data = ['admin_id' => $adminInfo['admin_id'],'admin_name' => $adminInfo['admin_name'],
];
$demoStr = json_encode($data,JSON_UNESCAPED_UNICODE);
$authorization = passportEncrypt($demoStr);Cookie::set('Auth-stark', $authorization,['prefix' => 'think', 'expire' => 3600]
);//解密
$json = passportDecrypt($authorization);
if(mb_strlen($json) > 0){$demoData = json_decode($json,true);
}

Token 登录

由于服务器端需要对接大量的客户端,也就需要存放大量的 SessionId,这样会导致服务器压力过大、无法避免 CSRF 攻击等缺点,我们可以使用 Token 的登录方式。

Token是通过服务端生成的一串字符串,以作为客户端请求的一个令牌。当第一次登录后,服务器会生成一个 Token 并返回给客户端,客户端后续访问时,只需带上这个 Token 即可完成身份认证,很多企业使用JWT的技术来进行登录验证方式。

用户首次登录

在这里插入图片描述

1、用户访问 www.stark.com/login,输入账号密码,并点击登录。
2、服务器端验证账号密码无误,创建 Token
3、服务器端将 Token 返回给客户端,由客户端存储在Header头信息里。

后续页面访问

在这里插入图片描述

1、用户访问 www.stark.com/login 时,带上第一次登录时获取的 Token
2、服务器端验证该 Token ,有效则身份验证成功,无效则踢回重新的登录。

Token 生成方式

最常见的 Token 生成方式是使用 JWT(Json Web Token),它是一种简洁的、自包含的方法,用于通信双方之间以 JSON 对象的形式安全的传递信息。

答案其实就在 Token 字符串中,其实 Token 并不是一串杂乱无章的字符串,而是通过多种算法拼接组合而成的字符串。

JWT 算法主要分为 3 个部分:header(头信息),playload(消息体),signature(签名)。

  • header 部分指定了该 JWT 使用的签名算法;
  • playload 部分表明了 JWT 的意图;
  • signature 部分为 JWT 的签名,主要为了让 JWT 不能被随意篡改。
JWT Token 技术实现

Compose 安装 Jwt 的两种方式,我使用的是6.10版本 :

## 安装
composer require firebase/php-jwt 6.10

使用 composer.json 安装,加入文件,使用composer install

"require": {"firebase/php-jwt": "^6.10"
}

Jwt 主要是进行加密和解密,$payload定义的是你需要存储的数组信息:

public static function encode(int $adminId = 0): string
{$redis = new Redis(config('cache.stores.redis'));$secretKey = Env::get("JWT.key"); // 获取JWT生成签名的密钥$alg = Env::get("JWT.alg"); // 获取JWT加密算法$payload = ['admin_id' => $adminId, // 存储用户ID'exp' => time() + Env::get("JWT.exp"), // 设定过期时间];$jwt = JWT::encode($payload, $secretKey, $alg); // 生成JWT令牌$token = config('prefix.auth');$redis->set($token.$adminId, $jwt,Env::get("JWT.exp") - rand(10,99));return $jwt;
}

解密的逻辑:

public static function decode(string $AccessToken = ''){$secretKey = Env::get("JWT.key"); // 获取JWT生成签名的密钥$alg = Env::get("JWT.alg"); // 获取JWT加密算法$secretKeyObj = new Key($secretKey,$alg);$headers = new stdClass();return JWT::decode($AccessToken, $secretKeyObj,$headers); // 使用JWT解密Token
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • WPF DataGrid 动态修改某一个单元格的样式
  • Scrapy爬虫IP代理池:提升爬取效率与稳定性
  • 10年408考研真题-数据结构
  • Ubuntu下使用 python搭建服务实现从web端远程配置设备网口
  • 【服务器入门】Linux系统基础知识
  • JS | 详解浏览器存储机制cookies、sessionStorage和localStorage的区别
  • 小程序组件间通信
  • Oracle 数据库常用命令与操作指南
  • 【乐企】基础版接口代码实现
  • 【iOS】引用计数(一)
  • 0基础学习HTML(十一)列表
  • xilinx hbm ip运用
  • 什么是堡垒机?运维为什么需要堡垒机?
  • Apache James配置连接达梦数据库
  • ldd可以显示出程序启动时需要静态加载的动态库的完整列表
  • 03Go 类型总结
  • 2017前端实习生面试总结
  • C语言笔记(第一章:C语言编程)
  • Java 网络编程(2):UDP 的使用
  • leetcode388. Longest Absolute File Path
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • npx命令介绍
  • Python实现BT种子转化为磁力链接【实战】
  • SpingCloudBus整合RabbitMQ
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 入门到放弃node系列之Hello Word篇
  • 微信小程序填坑清单
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • 树莓派用上kodexplorer也能玩成私有网盘
  • ​ 无限可能性的探索:Amazon Lightsail轻量应用服务器引领数字化时代创新发展
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (Python第六天)文件处理
  • (动手学习深度学习)第13章 计算机视觉---图像增广与微调
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (转)程序员技术练级攻略
  • (转)我也是一只IT小小鸟
  • (转载)微软数据挖掘算法:Microsoft 时序算法(5)
  • ***测试-HTTP方法
  • .NET命令行(CLI)常用命令
  • .net专家(张羿专栏)
  • /usr/local/nginx/logs/nginx.pid failed (2: No such file or directory)
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法
  • :“Failed to access IIS metabase”解决方法
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [1127]图形打印 sdutOJ
  • [12] 使用 CUDA 加速排序算法
  • [202209]mysql8.0 双主集群搭建 亲测可用
  • [2023-年度总结]凡是过往,皆为序章