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

news2024/7/4 5:11:18

文章目录

  • 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

    @Override
    public 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

    @Override
    public 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 {
    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public 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);
            //设置响应体:Result
            JsonObject 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);
    }

    @Override
    public 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 {
    @Resource
    private RedisTemplate redisTemplate;
    public static ThreadLocal<UserInfo> THREAD_LOCAL = new ThreadLocal();
    @Override
    public 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;
    }

    @Override
    public 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 {
    @Resource
    private SpzxServiceAuthInterceptor spzxServiceAuthInterceptor;

    @Override
    public 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

    @Override
    public 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.coloradmin.cn/o/1821948.html

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

相关文章

FlashDB的TS数据库的标准ANSI C移植验证

本文目录 1、引言2、环境准备3、修改驱动4、验证 文章对应视频教程&#xff1a; 暂无&#xff0c;可以关注我的B站账号等待更新。 点击图片或链接访问我的B站主页~~~ 1、引言 在当今数据驱动的时代&#xff0c;高效可靠的数据存储与管理对于嵌入式系统及物联网(IoT)应用至关重…

DSP教学实验箱_数字图像处理_操作教程:5-1 图像旋转

一、实验目的 学习图像旋转的原理&#xff0c;掌握图像的读取方法&#xff0c;并实现图像旋转。 二、实验原理 图像旋转 图像的旋转是指以图像的某一点为原点以逆时针或顺时针旋转一定的角度。其本质是以图像的中心为原点&#xff0c;将图像上的所有像素都旋转一个相同的角…

Axure中继器交互效果

部件库预览链接&#xff1a; https://ezd11a.axshare.com&#xff08;请与班主任联系获取原型文档&#xff09; 支持版本: Axrure RP 8 文件大小: 109KB 文档内容介绍 “翻页”效果 “排序”效果 “全反选”效果 “筛选”效果 “删除”效果 免费领取资料 添加班主任回复 “…

ctfshow-web入门-命令执行(web43-web52)关于黑洞“ >/dev/null 2>1“的处理与绕过

目录 1、web43 2、web44 3、web45 4、web46 5、web47 6、web48 7、web49 8、web50 9、web51 10、web52 1、web43 在上一题 ‘黑洞’ 的基础上新增过滤&#xff1a; preg_match("/\;|cat/i", $c) 问题不大&#xff0c;我们不用分号和 cat 就行&#xff1a;…

Postman接口测试工具详解(高清图例)

一、引言 1. 介绍接口测试的重要性 在当今软件开发领域&#xff0c;接口&#xff08;API&#xff09;已成为不同系统、服务或组件之间交互的桥梁。随着微服务架构的普及&#xff0c;接口的重要性日益凸显。然而&#xff0c;接口的复杂性和多样性也带来了诸多挑战&#xff0c;其…

数据结构笔记补充问题

1、假设线性表L采用单链表存储结构&#xff0c;设计一个算法&#xff0c;在L的数据元素最大值之前插入&#xff08;假设L的各个数据元素值不同&#xff09;数据元素x。 基本思想&#xff0c;先查找到最大元素对应的结点&#xff0c;再在之前插入x对应的结点&#xff1b; 设计算…

我的创作纪念日(1825天)

Ⅰ、机缘 1. 记得是大一、大二的时候就听学校的大牛说&#xff0c;可以通过写 CSDN 博客&#xff0c;来提升自己的代码和逻辑能力&#xff0c;虽然即将到了写作的第六个年头&#xff0c;但感觉这句话依旧受用; 2、今年一整年的创作都没有停止&#xff0c;本年度几乎是每周都来…

DTU为何应用如此广泛?

1.DTU是什么 DTU(数据传输单元)是一种无线终端设备&#xff0c;它的核心功能是将串口数据转换为IP数据或将IP数据转换为串口数据&#xff0c;并通过无线通信网络进行传送。DTU通常内置GPRS模块&#xff0c;能够实现远程数据的实时传输&#xff0c;广泛应用于工业自动化、远程监…

抓包工具 Wireshark 的下载、安装、使用、快捷键

目录 一、什么是Wireshark&#xff1f;二、Wireshark下载三、Wireshark安装四、Wireshark使用4.1 基本使用4.2 过滤设置1&#xff09;捕获过滤器2&#xff09;显示过滤器 4.3 过滤规则1&#xff09;捕获过滤器-规则语法2&#xff09;显示过滤器-规则语法 4.4 常用的显示过滤器规…

纵深发力 持续推进,富格林平台发展势头喜人

自2024年2月1日正式上线以来,富格林互联网投融资平台已迅速崛起,吸引了业内专家学者的高度认可以及广大投资者的青睐。平台规模持续扩大,目前累计注册用户已超过10万人,总投资额突破50亿美元。这一卓越表现不仅体现了平台的稳健运营和出色的投资项目,也展示了其在互联网投融资领…

探索Napier:Kotlin Multiplatform的日志记录库

探索Napier&#xff1a;Kotlin Multiplatform的日志记录库 在现代软件开发中&#xff0c;日志记录是不可或缺的部分&#xff0c;它帮助开发者追踪应用的行为和调试问题。对于Kotlin Multiplatform项目而言&#xff0c;能够在多个平台上统一日志记录的方法显得尤为重要。Napier…

在IDEA中连接数据库

1.点击侧边栏的Database 2.选中你要连接的数据库类型 3.输入用户名、密码&#xff0c;测试连接&#xff0c;没有驱动的话先下载下驱动 4.发现没有数据库&#xff0c;点击1 of 14&#xff0c;选择All schemas&#xff0c;即可显示全部数据库 5.执行sql 如果对您有帮助的话记…

【通义灵码-你的智能编程助手】

通义灵码是由阿里云推出的智能编码辅助工具&#xff0c;基于通义大模型&#xff0c;旨在提高开发者的编码效率和流畅度。它具备以下功能&#xff1a; 「通义灵码&#xff0c;助力你高效 AI 编码」 点击前往使用 行级/函数级实时续写&#xff1a;在编码过程中&#xff0c;根据…

k8s 自动伸缩机制-------HPA 超详细解读

目录 在K8s中扩缩容分为两种&#xff1a; 前言 弹性伸缩是根据用户的业务需求和策略&#xff0c;自动“调整”其“弹性资源”的管理服务。通过弹性伸缩功能&#xff0c;用户可设置对定时、周期或监控策略&#xff0c;恰到好处地增加或减少“弹性资源”&#xff0c;并完成实例…

【ASE】笔记总结

这里写自定义目录标题 ASE 介绍ASE 的安装文件格式的转化命令行操作图形界面操作Python代码操作[2]支持的文件转化格式 ASE&#xff08;三&#xff09;&#xff1a;图形界面查看/建立/修改结构图形界面召唤查看结构 python代码查看/建立结构读写、查看结构建立结构分子 周期性体…

软件测试分类介绍

大家好&#xff0c;软件测试是确保软件质量的关键环节之一&#xff0c;通过对软件系统的各个方面进行测试&#xff0c;可以发现和解决潜在的问题&#xff0c;提高软件的稳定性、可靠性和用户满意度。在软件测试领域&#xff0c;根据测试的目的、方法和对象的不同&#xff0c;可…

Linux常⽤服务器构建-ssh和scp

目录 1.ssh <1>ssh介绍 <2>安装ssh A.安装ssh服务器 B.远程登陆 <3>使⽤ssh连接服务器 2.scp 本地⽂件复制到远程&#xff1a; 本地⽬录复制到远程&#xff1a; 远程⽂件复制到本地&#xff1a; 远程⽬录复制到本地&#xff1a; 1.ssh <1>…

VMware ESXi 8.0U2c macOS Unlocker OEM BIOS ConnectX-3 网卡定制版 (集成驱动版)

VMware ESXi 8.0U2c macOS Unlocker & OEM BIOS ConnectX-3 网卡定制版 (集成驱动版) 发布 ESXi 8.0U2 集成驱动版&#xff0c;在个人电脑上运行企业级工作负载 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-8-u2-sysin/&#xff0c;查看最新版。原创作…

ubuntu gitlab 部署 私有git库

我的版本 ubuntu-22.04.2-live-server-amd64 GitLab 社区版 v17.0.1 注意剩余硬盘需要3GB以上 一、更新软件 sudo apt update二、gitLab 需要一些依赖项才能正常运行 sudo apt install -y curl openssh-server ca-certificates postfix1、出现邮件 选择 “Internet Site”并…

农业领域科技查新点提炼方法附案例!

农业学科是人类通过改造和利用生物有机体(植物、动物、微生物等)及各种自然资源(光、热、水、土壤等)生产出人类需求的农产品的过程&#xff0c;人类在这一过程中所积累的科学原理、技术、工艺和技能&#xff0c;统称为农业科学技术&#xff0c;该领域具有研究范围广、综合性强…