JustAuth Illegal state xx问题

news2024/11/24 1:38:13

排查

  1. 起因
    image.png
    服务上线生产环境后使用飞书登录有些时候会登录失败,查看日志出现以上错误Illegal state [FEISHU],但是测试环境没有出现这个情况

  2. 排查

经过排查发现是JustAuth 报的错
image.png

  1. 分析出现原因

在JustAuth找到出现原因和解决方案
原文地址:异常相关问题 | JustAuth

异常原因

  1. 单机的情况
    • state 默认有效期为3分钟(#AuthCacheConfig.java(opens new window)),第三方回调会开发者服务器后,因为异常原因在3分钟内没有处理回调请求,此时会抛出该异常。
  2. 集群的情况
    • 默认 state 是缓存到 map 中,当开发者的服务为集群时,不同集群间的内存缓存无法共享,抛出该异常。具体异常流程为:有 AB 两台服务器, A 服务器生成授权链接(同时生成 state 并存到 A 服务器的本机内存中),第三方登录完回调到了 B 服务器,此时 B 服务器内存中没有 state 缓存,并且无法访问到 A 服务器的内存。 系统抛出异常。
  3. 内网穿透的情况
    • 服务部署到云端,通过内网穿透到本机。在云端生成授权链接(同时生成 state 并存到云端服务器的内存中),回调请求穿透到本地,异常流程参考上面 “集群情况”。
  4. 前后端分离的情况
    • 项目实现前后端分离,并且生成第三方授权链接时为前端项目自行拼接,未使用 JA 提供的 authorize 方法。JA 在处理 code 换 token 时,默认会校验 state 是否存在,前端自己拼接的链接授权后,即使第三方返回了 state,但因为没有使用 JA 提供的 authorize 方法,所以缓存中并不存在 state,因此会导致验证失败。

解决方案

  • 针对第一种情况,先排查是否存在异常情况,然后具体分析为什么会延迟3分钟(是否本地在进行 DEBUG?是否第三方授权时长时间未点击确认授权)。最后可以适当将AuthCacheConfig.java#timeout(opens new window)参数值调高。
  • 针对第二种情况,建议使用自定义state缓存
  • 针对第三种情况,可临时将 AuthConfig.java#ignoreCheckState(opens new window)参数设为 true,待测试完成后,再将配置修改回来(建议仅本地测试使用,如需上线,不建议将ignoreCheckState设为 true)
  • 针对第四种情况,可将 AuthConfig.java#ignoreCheckState(opens new window)参数设为 true(仅此情况下,才建议将ignoreCheckState设为 true)
  • 如果不属于以上情况,另外还可以使用临时解决方案:将 AuthConfig.java#ignoreCheckState(opens new window)参数设为 true。至于为何将该条标注为【不建议】,请参考下图:

  1. 结合异常原因分析本次生产出现这个异常的原因
  • 我们的测试环境是单台机器所以不会出现这个问题
  • 我们这个服务在生产部署了2个
  • 所以异常原因是集群导致的state异常
  1. 解决方案
  • 快速临时解决方案: 停掉一个服务(快速解决问题,让服务可用)
  • 集群解决方案:自定义state缓存

JustAuth 自定义state缓存(redis缓存)

  1. 添加redis依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 添加redis配置
# 集成redis实现自定义的state缓存
spring.redis.database=0
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=xxxx
  1. 实现state缓存接口
package me.zhyd.justauth;

import me.zhyd.oauth.cache.AuthCacheConfig;
import me.zhyd.oauth.cache.AuthStateCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * 扩展Redis版的state缓存
 *
 * @author yadong.zhang (yadong.zhang0415(a)gmail.com)
 * @version 1.0
 * @date 2019/10/24 13:38
 * @since 1.8
 */
@Component
public class AuthStateRedisCache implements AuthStateCache {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private ValueOperations<String, String> valueOperations;

    @PostConstruct
    public void init() {
        valueOperations = redisTemplate.opsForValue();
    }

    /**
     * 存入缓存,默认3分钟
     *
     * @param key   缓存key
     * @param value 缓存内容
     */
    @Override
    public void cache(String key, String value) {
        valueOperations.set(key, value, AuthCacheConfig.timeout, TimeUnit.MILLISECONDS);
    }

    /**
     * 存入缓存
     *
     * @param key     缓存key
     * @param value   缓存内容
     * @param timeout 指定缓存过期时间(毫秒)
     */
    @Override
    public void cache(String key, String value, long timeout) {
        valueOperations.set(key, value, timeout, TimeUnit.MILLISECONDS);
    }

    /**
     * 获取缓存内容
     *
     * @param key 缓存key
     * @return 缓存内容
     */
    @Override
    public String get(String key) {
        return valueOperations.get(key);
    }

    /**
     * 是否存在key,如果对应key的value值已过期,也返回false
     *
     * @param key 缓存key
     * @return true:存在key,并且value没过期;false:key不存在或者已过期
     */
    @Override
    public boolean containsKey(String key) {
        return redisTemplate.hasKey(key);
    }
}
  1. 获取Request(以飞书为例)
// 1. 注入新添加的cache
@Autowired
private AuthStateRedisCache stateRedisCache;

// 2. 创建request时传入stateRedisCache
AuthRequest authRequest = new AuthFeishuRequest(AuthConfig.builder()
      .clientId("clientId")
      .clientSecret("clientSecret")
      .redirectUri("redirectUri")
      .build(), stateRedisCache);// 此处传入自定义实现的类

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

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

相关文章

用大模型实现PPT可视化几种思路

https://zhuanlan.zhihu.com/p/700685802 背景 前面一篇文章已经介绍了如何根据用户输入&#xff0c;用大模型实现内容检索、分析、脑图可视化的链路。然而往往投研团队需要针对重要新闻做组内分析解读&#xff0c;需要用ppt的方式来展现&#xff1b;那么优美可能让大模型直…

【全开源】Java同城服务同城信息同城任务发布平台小程序APP公众号源码

&#x1f4e2; 连接你我&#xff0c;让任务触手可及 &#x1f31f; 引言 在快节奏的现代生活中&#xff0c;我们时常需要寻找一些便捷的方式来处理生活中的琐事。同城任务发布平台系统应运而生&#xff0c;它为我们提供了一个高效、便捷的平台&#xff0c;让我们能够轻松发布…

【最新鸿蒙应用开发】——沙箱机制是什么?作用?场景?

沙箱机制 1. 什么是沙箱机制&#xff1f; 1.1. 概念 在操作系统当中&#xff0c;沙箱机制&#xff08;Sandboxing&#xff09;是一种安全机制&#xff0c;用于限制程序代码的访问权限&#xff0c;防止恶意软件对系统造成破坏。在沙箱环境中&#xff0c;程序只能访问特定的资…

Docker 学习总结(83)—— 配置文件daemon.json介绍及优化建议

一、daemon.json 文件概述 daemon.json是Docker守护进程的配置文件,它允许系统管理员自定义Docker守护程序的行为。此文件通常位于/etc/docker/目录下。通过修改daemon.json,可以调整Docker守护进程的多种设置,包括网络配置、日志记录、存储驱动等。 二、daemon.json 文件结…

YoloV8改进策略:Block篇|MobileNetV4——移动生态系统的通用模型

文章目录 摘要1、引言2、相关工作3、硬件无关的帕累托效率4、通用反向瓶颈5、Mobile MQA6、MNv4模型设计6.1、精炼NAS以增强架构6.2、MNv4模型的优化 7、结果7.1、ImageNet分类 8、增强蒸馏方案9、结论10、致谢A、搜索空间细节B、基准测试方法论C、ImageNet-1k分类任务的训练设…

Linux之线程及线程安全详解

前言&#xff1a;在操作系统中&#xff0c;进程是资源分配的基本单位&#xff0c;那么线程是什么呢&#xff1f;线程是调度的基本单位&#xff0c;我们该怎么理解呢&#xff1f; 目录 一&#xff0c;线程概念理解 二&#xff0c;Linux里面的线程原理 三&#xff0c;为什么要…

哈夫曼树的构造,哈夫曼树的存在意义--求哈夫曼编码

一:哈夫曼树的构造 ①权值,带权路径长度。 ②一组确定权值的叶子节点可以构造多个不同的二叉树,但是带权路径长度min的是哈夫曼树 ③算法基本思想及其实操图片演示 注:存储结构和伪代码 1 初始化: 构造2n-1棵只有一个根节点的二叉树,parent=rchild=lchild=-1; 其中…

忆恒创源国产系列新品 —— PBlaze7 7A40 取得 PCI-SIG 兼容性认证

在此前报道中&#xff0c;我们曾预告了忆恒创源国产系列 PCIe 5.0 SSD 新品 —— PBlaze7 7A40&#xff0c;今天&#xff0c;这款 SSD 已经顺利通过 PCI-SIG 的严格测试并出现在 Integrators List 集成商列表当中&#xff0c;标志着距离 PBlaze7 7A40 的正式发布又近了一步。 正…

Spring Boot框架基础

文章目录 1 Spring Boot概述2 Spring Boot入门2.1 项目搭建2.2 入门程序 3 数据请求与响应3.1 数据请求3.2 数据响应 4 分层解耦4.1 三层架构4.2 控制反转4.3 依赖注入 5 参考资料 1 Spring Boot概述 Spring是Java EE编程领域的一个轻量级开源框架&#xff0c;是为了解决企业级…

乐高小人分类项目

数据来源 LEGO Minifigures | Kaggle 建立文件目录 BASE_DIR lego/star-wars-images/ names [YODA, LUKE SKYWALKER, R2-D2, MACE WINDU, GENERAL GRIEVOUS ] tf.random.set_seed(1)# Read information about dataset if not os.path.isdir(BASE_DIR train/):for name in …

Edge 工作区是什么?它都有哪些作用?

什么是工作区 Edge 工作区是什么&#xff1f;它是微软 Edge 浏览器中的一个功能&#xff0c;在帮助用户更好地组织和管理他们的浏览会话。通过工作区&#xff0c;用户可以创建多个独立的浏览环境&#xff0c;每个工作区内包含一组相关的标签页和浏览器设置。这使得用户能够根据…

asp.net core使用httpclient

主要讲解常见的get请求和post请求 GET var client new HttpClient(); //3秒钟不响应就超时 client.TimeoutTimeSpan.FromSeconds(3); using HttpResponseMessage response await client.GetAsync("todos/3"); var jsonResponse await response.Content.ReadAsSt…

变压器绕线完成之后要做的事

1 调整感量&#xff1a;测主绕组电感量&#xff0c;通过磨气隙或垫气隙&#xff0c;测得感量没错以后&#xff0c;用胶带封装磁芯 2 测验同名端是否正确&#xff1a;两绕组首尾相连&#xff0c;测试连接后的总感量&#xff0c;是否比感量大的那个绕组还大。如果是&#xff0c;…

Allegro热风焊盘制作教程

阿里狗热风焊盘制作教程 打开PCB Editor&#xff0c;新建Flash symbol&#xff0c;最好保存在与Pad文件同一个路径 点击Setup–>Design Parameter Editor,设置mm单位&#xff0c;在设置画布&#xff0c;把原点提上去&#xff0c;点击Apply和OK 把视野调整到原点 点击Setup–…

vue面试题2-根据以下问题回答

以下是针对提供的关于Vue的问题的回答&#xff1a; Vue的基本原理&#xff1a; Vue.js是一个流行的JavaScript框架&#xff0c;用于构建用户界面和单页面应用。其基本原理包括响应式数据、模板、组件系统、指令、生命周期钩子和虚拟DOM。 双向数据绑定的原理&#xff1a; Vue通…

咖啡机器人如何精准控制液位流量

在如今快节奏的生活中&#xff0c;精确控制液位流量的需求愈发迫切&#xff0c;特别是在咖啡机器人等精密设备中。为了满足这一需求&#xff0c;工程师们不断研发出各种先进的技术&#xff0c;以确保液体流量的精准控制。其中&#xff0c;霍尔式流量计和光电式流量计就是两种常…

转让北京海淀成立满1年拍卖公司许可证条件和流程

拍卖经营批准证书是拍卖企业经营所需的许可&#xff0c;是为了维护拍卖秩序&#xff0c;保护拍卖活动各方合法权益而颁发的合法凭证。其中个人物品&#xff0c;公司物品&#xff0c;或者国有资源的拍卖可通过普通拍卖资质进行拍卖。而文物古董拍卖类的需取得文物拍卖经营许可证…

google keybox.xml格式 内容有哪些 Keybox数量、设备ID、算法的 私钥 公钥 证书链 (ECDSA即ECC, RSA)

根据您提供的文件内容&#xff0c;keybox.xml 文件包含以下主要信息&#xff1a; Keybox数量 ([NumberOfKeyboxes](file:///d%3A/010F200/svn/ProduceToolMfc/FtSmartPos/FtSmartPos/ToolBydMes/httpclient/e%3A%5CGoogleKey%5CLinux_AttestationKeyboxPack_Tool%5CLinux_Atte…

【吊打面试官系列】简述在 MySQL 数据库中 MyISAM 和 InnoDB 的区别 ?

大家好&#xff0c;我是锋哥。今天分享关于 【简述在 MySQL 数据库中 MyISAM 和 InnoDB 的区别 &#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 简述在 MySQL 数据库中 MyISAM 和 InnoDB 的区别 &#xff1f; MyISAM&#xff1a; 不支持事务&#xff0c;但是…

全网最全!场外个股期权的询价下单流程的详细解析

场外个股期权的询价下单流程 场外个股期权交易&#xff0c;作为在交易所外进行的个性化期权交易方式&#xff0c;为投资者提供了更加灵活和定制化的交易选择。以下是场外个股期权询价下单流程的详细步骤&#xff1a; 文章来源/&#xff1a;财智财经 第一步&#xff1a;明确交…