H5单点登录分析介绍(登录状态检验状态透传分析)

文章目录

  • 1、单点登录解决方案
    • 1.1、后端保存登录状态
    • 1.2、token模式
  • 2、user服务-登录接口
    • 2.1、UserController
    • 2.2、UserInfoServiceImpl
    • 2.3、载荷
    • 2.4、响应
    • 2.5、Redis Desktop Manager
  • 3、user服务-登录成功获取用户信息回显
    • 3.1、UserController
    • 3.2、UserInfoServiceImpl
    • 3.3、响应
  • 4、登录状态验证&状态透传分析
    • 4.1、gateway-过滤器统一校验登录状态
      • 4.1.1、GlobalAuthFilter
    • 4.2、登录状态透传拦截器
      • 4.2.1、SpzxServiceAuthInterceptor
      • 4.2.2、H5SpzxWebMvcConfigurer
      • 4.2.3、@EnableSpzxServiceAuth
      • 4.2.4、UserInfoServiceImpl
  • 5、登录校验状态透传总结

1、单点登录解决方案

  • 多个系统只有一个登录服务

1.1、后端保存登录状态

在这里插入图片描述

1.2、token模式

在这里插入图片描述

2、user服务-登录接口

2.1、UserController

	@Operation( summary = "用户登录接口")@PostMapping("/login")public Result login(@RequestBody UserInfo userInfo) {String token = userInfoService.login(userInfo);return Result.ok(token);}

2.2、UserInfoServiceImpl

    @Overridepublic String login(UserInfo userInfo) {//1、校验参数String username = userInfo.getUsername();String password = userInfo.getPassword();if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {throw new SpzxException(ResultCodeEnum.LOGIN_PARAMS_ERROR, null);}//2、根据账号查询用户信息UserInfo dbUserInfo = this.getOne(Wrappers.lambdaQuery(UserInfo.class).eq(UserInfo::getUsername, username));if (dbUserInfo == null) {throw new SpzxException(ResultCodeEnum.LOGIN_USERNAME_ERROR, null);}//判断用户状态,用户状态校验if (dbUserInfo.getStatus() != 1) {throw new SpzxException(ResultCodeEnum.LOGIN_USER_STATUS_ERROR, null);}//3、账号存在,校验密码//使用明文密码 和 盐 采用注册的加密方式加密 和数据库密文比较String encodePwd = DigestUtils.md5DigestAsHex((DigestUtils.md5DigestAsHex(password.getBytes()) + dbUserInfo.getSalt()).getBytes());if (!encodePwd.equals(dbUserInfo.getPassword())) {throw new SpzxException(ResultCodeEnum.LOGIN_PASSWORD_ERROR, null);}//密码正确//4、生成token 缓存到redis中String token = IdUtil.getSnowflake(1, 1).nextIdStr();// 将用户密码重置为null,表示清除密码信息dbUserInfo.setPassword(null);// 将用户盐值重置为null,配合密码重置,确保安全性和一致性dbUserInfo.setSalt(null);redisTemplate.opsForValue().set("spzx:user:login:" + token, dbUserInfo, 7, TimeUnit.DAYS);//登录成功:更新用户最后一次登录的时间 和 ip地址ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = requestAttributes.getRequest();return token;}

2.3、载荷

{"username": "18947628476","password": "123456"
}

2.4、响应

{"code":200,"message":"SUCCESS","data":"1801188891328385024"}

在这里插入图片描述

2.5、Redis Desktop Manager

{"@class": "com.atguigu.spzx.model.entity.h5.UserInfo","id": 1774759294596579329,"createTime": ["java.util.Date","2024-04-01 19:22:44"],"updateTime": ["java.util.Date",1718243055000],"deleted": false,"username": "18947628476","password": null,"nickName": "小弟","avatar": "https://cdn.apifox.com/app/project-icon/builtin/16.jpg","sex": null,"phone": null,"memo": null,"openId": null,"unionId": null,"lastLoginIp": null,"lastLoginTime": null,"status": 1,"salt": null
}

3、user服务-登录成功获取用户信息回显

在这里插入图片描述

3.1、UserController

    //auth:以后需要登录验证的接口会在路径中添加一层auth   前端访问时需要在请求头携带token@Operation( summary = "查询用户信息回显接口")@GetMapping("/auth/getCurrentUserInfo")public Result getCurrentUserInfo(@RequestHeader(value = "token",required = false)String token) {UserInfoVo userInfoVo = userInfoService.getCurrentUserInfo(token);return Result.ok(userInfoVo);}

3.2、UserInfoServiceImpl

    @Overridepublic UserInfoVo getCurrentUserInfo(String token) {UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get("spzx:user:login:" + token);if (userInfo == null) {//登录状态失效throw new SpzxException(ResultCodeEnum.LOGIN_STATUS_ERROR, null);}//UserInfo userInfo = SpzxServiceAuthInterceptor.THREAD_LOCAL.get();UserInfoVo userInfoVo = new UserInfoVo();userInfoVo.setNickName(userInfo.getNickName());userInfoVo.setAvatar(userInfo.getAvatar());return userInfoVo;}

3.3、响应

{"code": 200,"message": "SUCCESS","data": {"nickName": "小弟","avatar": "https://cdn.apifox.com/app/project-icon/builtin/16.jpg"}
}

4、登录状态验证&状态透传分析

在这里插入图片描述

4.1、gateway-过滤器统一校验登录状态

4.1.1、GlobalAuthFilter

package com.atguigu.spzx.gateway.filter;
import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
import com.atguigu.spzx.model.result.ResultCodeEnum;
import jakarta.annotation.Resource;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {@Resourceprivate RedisTemplate redisTemplate;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//1、判断请求路径是否需要验证登录状态ServerHttpRequest request = exchange.getRequest();String path = request.getURI().getPath();AntPathMatcher matcher = new AntPathMatcher();//1.1 不需要:直接放行if (!matcher.match("/**/auth/**", path)) {return chain.filter(exchange);}//1.2 需要:验证//2、获取头中的token到redis中查询登录状态 存在放行不存在返回一个Restful风格的响应报文(响应体设置一个Result对象的json)String token = request.getHeaders().getFirst("token");//redisTemplate必须和 微服务的配置一样if (StringUtils.isEmpty(token) || !redisTemplate.hasKey("spzx:user:login:" + token)) {//token不存在 或者 token 过期ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.OK);//设置状态码//设置响应头:指定响应体内容的类型response.getHeaders().add("Content-Type", MediaType.APPLICATION_JSON_UTF8_VALUE);//设置响应体:ResultJsonObject jsonObject = new JsonObject();jsonObject.addProperty("code", ResultCodeEnum.LOGIN_STATUS_ERROR.getCode());jsonObject.addProperty("message", ResultCodeEnum.LOGIN_STATUS_ERROR.getMessage());String json = jsonObject.toString();DataBuffer buffer = response.bufferFactory().wrap(json.getBytes());//返回自定义响应报文:不放行return response.writeWith(Mono.just(buffer));}//登录状态有效 放行return chain.filter(exchange);}@Overridepublic int getOrder() {return -1;}
}

4.2、登录状态透传拦截器

4.2.1、SpzxServiceAuthInterceptor

package com.atguigu.spzx.common.handler.interceptor;
import com.atguigu.spzx.model.entity.h5.UserInfo;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class SpzxServiceAuthInterceptor implements HandlerInterceptor {@Resourceprivate RedisTemplate redisTemplate;public static ThreadLocal<UserInfo> THREAD_LOCAL = new ThreadLocal();@Overridepublic boolean preHandle(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("token");UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get("spzx:user:login:" + token);THREAD_LOCAL.set(userInfo);return true;}@Overridepublic void afterCompletion(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {THREAD_LOCAL.remove();}
}

4.2.2、H5SpzxWebMvcConfigurer

package com.atguigu.spzx.common.handler.interceptor;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class H5SpzxWebMvcConfigurer implements WebMvcConfigurer {@Resourceprivate SpzxServiceAuthInterceptor spzxServiceAuthInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(spzxServiceAuthInterceptor).addPathPatterns("/**/auth/**");}
}

4.2.3、@EnableSpzxServiceAuth

package com.atguigu.spzx.common.handler.interceptor;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(value = {SpzxServiceAuthInterceptor.class, H5SpzxWebMvcConfigurer.class})
public @interface EnableSpzxServiceAuth {
}

4.2.4、UserInfoServiceImpl

    @Overridepublic UserInfoVo getCurrentUserInfo(String token) {/*UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get("spzx:user:login:" + token);if (userInfo == null) {//登录状态失效throw new SpzxException(ResultCodeEnum.LOGIN_STATUS_ERROR, null);}*/UserInfo userInfo = SpzxServiceAuthInterceptor.THREAD_LOCAL.get();UserInfoVo userInfoVo = new UserInfoVo();userInfoVo.setNickName(userInfo.getNickName());userInfoVo.setAvatar(userInfo.getAvatar());return userInfoVo;}

在这里插入图片描述

5、登录校验状态透传总结

在这里插入图片描述

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

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

相关文章

Unity资源 之 最受欢迎的三消游戏开发包 - Bubble Shooter Kit 【免费领取】

三消游戏开发包 - Bubble Shooter Kit 免费领取 前言资源包内容领取兑换码 前言 如果你是一名 Unity 游戏开发者&#xff0c;并且正在寻找一种快速、简单的方式来创建自己的三消游戏&#xff0c;那么 Bubble Shooter Kit 就是你所需要的。 资源包内容 Bubble Shooter Kit 是…

[Qt]Qt中的QPainter绘制在哪的问题

QPainter绘制的内容是在哪儿呢&#xff1f; QPainter 与不同的 QPainterDevice 类交互&#xff08;例如窗口、pixmap、printer 等&#xff09;&#xff0c;通过 QPainterDevice 的 begin() 和 end() 方法以及 QPaintDeviceMetrics 来控制绘画设备。 如果把 QImage 作为 QPainte…

英文语法工具Grammarly for Word下载和安装

前言&#xff1a;论文写作语法检查和润色的时候&#xff0c;可以用Grammarly进行帮助。 Grammarly for Word的下载、安装、使用 官网下载Grammarly for Microsoft Office安装GrammarlyWord使用GrammarlyGrammarly使用 官网下载Grammarly for Microsoft Office 地址&#xff1…

【全开源】ChatGPT 机器人公众号小程序h5源码开源交付支持二开

AI机器人系统对接OPENAI&#xff1a;智能互联的无限可能 &#x1f310; 一、引言&#xff1a;AI机器人系统与OPENAI的碰撞 在科技日新月异的今天&#xff0c;AI机器人系统正逐渐渗透到我们生活的各个角落。而当这一智能系统与全球领先的OPENAI技术相结合&#xff0c;又将擦出…

【CT】LeetCode手撕—33. 搜索旋转排序数组

目录 题目1-思路1-1 模式识别&#xff1a;1-2 二分模板 && 本质二分红色边界二分绿色边界 1-3 本题思路①二分出第一个区间②判断 target 在哪个区间③利用二分性质 2- 实现⭐33. 搜索旋转排序数组——题解思路 3- ACM实现 题目 原题连接&#xff1a;33. 搜索旋转排序…

MathTpye7最新版软件下载与安装步骤2024最新新手小白教程

在2024年&#xff0c;作为软件开发者的你&#xff0c;一定知道MathType这款广受欢迎的数学公式编辑器吧&#xff01;&#x1f4f1;&#x1f50b;&#x1f4b0;&#x1f9ee; MathType是一款功能强大的数学公式编辑工具。无论是学术研究&#x1f4da;还是数字教育&#x1f469;‍…

火车头采集怎么使用GPT等AI原创文章

火车头采集官方并没有GPT、百度文心一言AI、阿里通义千问AI、Kimi大模型等AI功能&#xff0c;但支持接入插件&#xff0c;可以编写相应人工智能AI原创文章插件&#xff08;火车头采集支持PHP和c#这2种语言的插件编写&#xff09;&#xff0c;或者导入第三方封装好的GPT等AI原创…

【数据结构与算法】图的基本概念

文章目录 图的基本概念定义常用术语有向图无向图简单图、多重图完全图&#xff08;简单完全图&#xff09;子图连通、连通图和连通分量强连通图、强连通分量边的权和网稠密图、稀疏图路径、路径长度和回路简单路径、简单回路距离有向树 图的基本概念 定义 图是一种非线性的逻…

【收藏】Web 前端知识体系精简【文末福利!】赠2024Web 前端/安全工程师资料视频教程+源码+课件

目录 JAVASCRIPT 篇 0、基础语法 1、函数原型链 2、函数作用域 3、函数指针 this 4、构造函数 new 5、闭包 6、单线程和异步队列 7、异步通讯 Ajax技术 8、DOM对象 document 9、事件系统 Event 10、全局对象 window CSS 篇 1、选择器 2、定位 3、浮动 4、盒子…

人脸识别系统---人脸对比

一、人脸对比 1.定义全局变量来存储选择的图片路径和标签 save_image1 None save_image2 None image_label1 None image_label2 None2.定义了一个名为compare_faces的函数&#xff0c;用于比较两张图片中的人脸是否相似 def compare_faces():if save_image1 and save_im…

linux环境打包QML程序

第一次打包linux下的QML程序&#xff0c;一路磕磕绊绊&#xff0c;如果有更好的方式&#xff0c;欢迎留言。 1、使用release编译出可执行文件&#xff0c;这一步大家都知道吧&#xff1b; 2、将可执行文件放入新建文件夹project中&#xff0c;同时创建copylib.sh文件&#xf…

魔众文库系统v6.7.0版本用户注册登录优化,已知问题修复

2024-06-14 更新日志 用户注册登录优化&#xff0c;已知问题修复 [新功能] Hidden 组件支持序列化类型&#xff0c;避免入库异常 [新功能] 增加命令执行函数和数组多键值排序方法 [新功能] 后台安全提醒修改密码链接不存在问题 [新功能] 优化 Nav 组件&#xff0c;支持链式…

远程开发端口转发

应用推荐场景&#xff1a; 1.服务器跑后台&#xff0c;本地出前端应用。 比如Stable Diffusion的大模型打标应用。 2.Docker容器服务器。 对于本地服务想要转出去&#xff0c;跑出来前端。该项能克服虚拟机的端口与ip访问问题。 正文&#xff1a; 涉及的软件&#xff1a; …

电压kV为什么k要小写,原因你知道吗?

国际标准的计量单位一般用小写。仅在涉及以名字命名的单位&#xff0c;比如伏特V、安培A、开尔文K、瓦特W等&#xff0c;为了表示对科学家前辈的尊重&#xff0c;就用大写&#xff0c;其余的非以人名命名的单位一般用小写。这里解释了为何V是大写。 其次&#xff0c;对于量词&…

二级造价师精选基础知识题库(含答案)

一.单项选择题: 1.大中型建设工程项目立项批准后&#xff0c;在工程开工前&#xff0c;应当由( )按照有关规定申请领取施工许可证。A.建设单位 B.施工单位 C.总承包单位 D.监理单位 2.建设单位申领建筑工程施工许可证后&#xff0c;既不开工又不申请延期或者超过延期时限的&a…

YOLOv10改进|采用ADown降采样模块有效融合

📚 专栏地址:《YOLOv10算法改进实战》 👉 独家改进,对现有YOLOv10进行二次创新,提升检测精度,适合科研创新度十足,强烈推荐 🌟 统一使用 YOLOv10 代码框架,结合不同模块来构建不同的YOLO目标检测模型。 💥 本博客包含大量的改进方式,降低改进难度,改进点包含【B…

14,15-EET/DHET Hypertension ELISA Kit--Detroit RD

用于14,15-EET/DHET测量的DH2与用于14,15-DHET测量的DH1相同。与DH2相比&#xff0c;与DH1的唯一区别是样品制备步骤&#xff08;而不是Elisa试剂盒&#xff09;&#xff0c;其中EET被化学改为DHET。 货号&#xff1a;DH2 名称&#xff1a;14,15-EET/DHET Hypertension ELISA…

C#——值类型和引用类型的区别详情

值类型和引用类型的区别 值类型 值类型&#xff1a; 常用的基本数据类型都是值类型&#xff1a;bool 、char、int、 double、 float、long 、 byte 、ulong、uint、枚举类型、 结构体类型等特点: 在赋值的过程当中&#xff0c;把值的本身赋值给另一个变量&#xff0c;再修改…

使用 PNPM 从零搭建 Monorepo,测试组件并发布

1 目标 通过 PNPM 创建一个 monorepo&#xff08;多个项目在一个代码仓库&#xff09;项目&#xff0c;形成一个通用的仓库模板。 这里以在该 monorepo 项目中搭建 web components 类型的组件库为例&#xff0c;介绍从仓库搭建、组件测试到组件发布的整个流程。 这个仓库既可…

gpt、llama大模型模型结构细节探索

参考&#xff1a; https://github.com/naklecha/llama3-from-scratch&#xff08;一定要看看&#xff09; https://github.com/karpathy/build-nanogpt/blob/master/play.ipynb 视频&#xff1a; https://www.youtube.com/watch?vl8pRSuU81PU https://tiktokenizer.vercel…