从授权校验看SpringBoot自动装配

背景

最近需要实现一个对于系统的授权检测功能,即当SpringBoot应用被启动时,需要当前设备是否具有有效的的授权许可信息,若无则直接退出应用。具体的实现方案请继续看下文。

环境

Ruoyi-Vue SpringBoot3 RuoYi-Vue: 🎉 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统,同时提供了 Vue3 的版本 - Gitee.comicon-default.png?t=O83Ahttps://gitee.com/y_project/RuoYi-Vue/tree/springboot3/

初始实现

基于文章开头所提到需求,很容易想到可以在主启动类中编写相关代码来实现,由于我们需要的是在类加载初期校验,并且我们可能需要从配置文件中获取部分信息,因此需要使用如下方法来编写代码。

首先在当前主启动类所在的包下新建utils包,用于校验代码的编写,

新建校验工具类InitCheckUtil,代码如下

@Component
public class InitCheckUtil {

    @Value("${init.key}")
    private String key;
    
    @PostConstruct
    public void check() {

        if (StringUtils.isBlank(key) || !"ruoyi".equals(key)) {
            System.out.println("系统未授权,请联系管理员");
            System.exit(0);
        }else{
            System.out.println("current key is: " + key + "system is authorized");
        }
    }
}

不难看出,这个校验工具的逻辑为,首先从配置文件(application.yml)中加载了init.key的值,配文件信息如下:

之后通过check方法来判断获取的key是否为 ruoyi ,若不满足条件则直接退出。执行代码后结果如下:

可以看到已经打印了当前key值,并表明系统已经进行了了授权。需要注意的是,这里的@PostConstruct注解确保了Spring容器启动时就会执行这个方法。

目前来看似乎已经完成了我们的需求,但是如果现在想要在项目启动前就执行呢,而不是等到容器加载时在校验,可以看到输出当前key信息之前已经有其它的日志信息,更为复杂的项目在启动时往往伴随着更多的前置初始化的东西,那么,如何在SpringBoot类启动前就进行校验呢?

ApplicationContextInitializer

上一小节我们已经实现了一个初步版本,而为了能够满足新的启动之前的即校验需求,我们需要做进一步的改动。首先可以想到的便是在主启动类中进行加载,直接在启动方法之前,使用创建InitCheckUtil对象的方式,然后调用其check方法。

如果此时直接启动项目,将会出现如下效果:

看起来似乎实现了启动前的校验,但是我们并没有更改配置文件中的key值,正常情况下服务应该是启动成功的状态。但目前状况的原因是由于我们现在的代码先于Spring容器执行,因此@Value注解将无法正常读取到key值,进而校验失败,因此InitCheckUtil类的代码变为:

public class InitCheckUtil {

    private String key;

    public InitCheckUtil(){}
    
    public InitCheckUtil(String key){
        this.key = key;
    }

    public void check() {
        

        if (StringUtils.isBlank(key) || !"ruoyi".equals(key)) {
            System.out.println("系统未授权,请联系管理员");
            System.exit(0);
        }else{
            System.out.println("current key is: " + key + ", system is authorized");
        }
    }
}

但由于没有了Spring容器的能力的加持,此时对于配置文件读取就无法直接使用@Value注解来获取了,因此我们现在使用使用一种新的方式来实现对配置文件的读取,即通过ApplicationContextInitializer 接口,它的作用在于当容器启动之前就可以读取配置文件中的值,从而满足我们当前的需求,具体实现如下,新建CheckConfigInitlnitializer类并实现 ApplicationContextInitializer 接口的 initialize 方法,在该方法中通过applicationContext获取ConfigurableEnvironment 对象,进而获取配置文件中的信息后传入校验类中实现校验:

public class CheckConfigInitializer implements ApplicationContextInitializer {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        String initKey = environment.getProperty("init.key");
        InitCheckUtil checkUtil = new InitCheckUtil(initKey);
        checkUtil.check();
    }
}

由于我们更改了配置文件的获取方式,因此主启动类的中内容也需要做相关的更改,如下所示增加了对于初始化器的注册,从而可以确保可以在整个容器启动之前完成校验。

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class RuoYiApplication
{
    public static void main(String[] args)
    {
        SpringApplication application = new SpringApplication(RuoYiApplication.class);
        application.addInitializers(new CheckConfigInitializer());
        application.run( args);
        System.out.println("(♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙  \n" +
                " .-------.       ____     __        \n" +
                " |  _ _   \\      \\   \\   /  /    \n" +
                " | ( ' )  |       \\  _. /  '       \n" +
                " |(_ o _) /        _( )_ .'         \n" +
                " | (_,_).' __  ___(_ o _)'          \n" +
                " |  |\\ \\  |  ||   |(_,_)'         \n" +
                " |  | \\ `'   /|   `-'  /           \n" +
                " |  |  \\    /  \\      /           \n" +
                " ''-'   `'-'    `-..-'              ");
    }
}

 此时系统可正常启动,并输出相应的校验信息如下

自动装配

在上一步中我们已经基本实现了对于文章开头提出需求问题的解决,但是若后续存在类似需求时需要我们不断往主主启动类中添加代码。这种方法看起来极为的不优雅,整个启动类会变得愈发臃肿。因此我们可以通过SpringBoot中的自动装配机制对上面的代码进行进一步的调整优化。

其实目前优化的方式严格意义上时上一步的另一种实现方式,这里将通过使用spring.factories文件来代替在主启动类中显式的注册初始化类。通过在项目当前模块的resources目录下新建META-INF 文件夹(不存在则新建),并新增 spring.factories 文件,该文件的内容将在Spring容器启动前进行扫描并加载,若为了实现通用性可将其迁移至common模块中,此处仅做展示用,方便起见未进行迁移。

 在spring.factories 文件中添加如下内容,其中 key 为 org.springframework.context.ApplicationContextInitialize 固定值,value 为我们自定义的实现的全包名。

org.springframework.context.ApplicationContextInitializer=com.ruoyi.utils.CheckConfigInitializer

这个时候就可以将启动类中的代码还原为原始的状态,再次启动程序后发现系统可以正常运行,其原理为,当SpringApplication初始化时通过SpringFactoriesLoader获取到配置在 META-INF/spring.factories 文件中的 ApplicationContextInitializer 的所有实现类,进而加载到容器中,而在这个过程中将实现对了系统启动的初步校验。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Unity】 HTFramework框架(五十七)通过Tag、Layer批量搜索物体

更新日期:2024年12月30日。 Github源码:[点我获取源码] Gitee源码:[点我获取源码] 索引 问题再现通过Tag搜索物体(SearchByTag)打开SearchByTag窗口搜索标记指定Tag的所有物体批量修改Tag搜索Undefined状态的所有物体 …

Unity2D无限地图的实现(简单好抄)

说明:本教程实现的是在2D游戏中玩家在游戏中上下左右移动的时候自动进行地图拼接的功能,如果你只想实现左右移动的无限地图,那么这篇博客也能起到一定参考作用。 思路 第一步: 创建一个10*10的2D游戏对象当做地图 第二步创建一个…

艾体宝方案丨全面提升API安全:AccuKnox 接口漏洞预防与修复

一、API 安全:现代企业的必修课 在现代技术生态中,应用程序编程接口(API)扮演着不可或缺的角色。从数据共享到跨平台集成,API 成为连接企业系统与外部服务的桥梁。然而,伴随云计算的普及与微服务架构的流行…

日期时间选择(设置禁用状态)

目录 1.element文档需要 2.禁用所有过去的时间 3.设置指定日期的禁用时间 <template><div class"block"><span class"demonstration">起始日期时刻为 12:00:00</span><el-date-pickerv-model"value1"type"dat…

SAP学习笔记 - 豆知识14 - Msg 番号 M7562 - 取引Type WL 对应的番号範囲中不存在2025年度 OMBT

这种类似的以前也写过&#xff0c;原因就是自动採番的番号没弄。 比如跨年了&#xff0c;那该新年度的番号范围没弄啊&#xff0c;就会出这种错误。 把番号范围给加一下就可以了。 1&#xff0c;现象 比如点 VL02N 出荷传票变更 画面&#xff0c;点 出库确认 就会出如下错误…

SpringBoot 集成 Activiti 7 工作流引擎

一. 版本信息 IntelliJ IDEA 2023.3.6JDK 17Activiti 7 二. IDEA依赖插件安装 安装BPM流程图插件&#xff0c;如果IDEA的版本超过2020,则不支持actiBPM插件。我的IDEA是2023版本我装的是 Activiti BPMN visualizer 插件。 在Plugins 搜索 Activiti BPMN visualizer 安装 创…

分布式版本管理工具——Git关联远程仓库(github+gitee)

Git远程仓库&#xff08;Github&#xff09;的基本使用 一、前言二、Git远程仓库介绍三、演示1. 关联github远程仓库2. 关联gitee&#xff08;码云&#xff09;远程仓库3. 重命名远程仓库名4. 移除远程仓库 四、结束语 一、前言 古之立大事者&#xff0c;不惟有超世之才&#x…

python-leetcode-删除有序数组中的重复项 II

80. 删除有序数组中的重复项 II - 力扣&#xff08;LeetCode&#xff09; class Solution:def removeDuplicates(self, nums: List[int]) -> int:n len(nums)if n < 2:return n # 如果长度小于等于 2&#xff0c;直接返回长度k 2 # 指针 k 指向下一个有效位置&#x…

欧科云链OKLink:比特币与以太坊“双重启动”将如何撬动市场?

近日&#xff0c;OKLink 与 137Labs 联合举办 X Space&#xff0c;围绕宏观经济环境、政策及机构投资的影响等话题&#xff0c;分享如何把握 Web3 中的潜在机会与辨别风险。OKG Research 首席研究员 Hedy、BuilderRocket Accelerator 研究合伙人 Vivienna、VC 分析员 Bunny、BU…

【Linux】Socket编程-UDP构建自己的C++服务器

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; UDP 网络编程 &#x1f98b; 接口讲解&#x1f98b; V1 版本 - echo server&#x1f98b; V2 版本 - DictServer&#x1f98b; V3 版本 - 简单聊天室 二&a…

创建型设计模式、结构型设计模式与行为型设计模式 上下文任务通用方案 设计模式 大全

设计模式&#xff08;Design Pattern&#xff09;是一种面向对象编程思想&#xff0c;分为创建型模式、结构型模式与行为型模式三大类&#xff0c;提供在特定上下文中解决常见任务通用方案&#xff0c;旨在让程序&#xff08;软件&#xff09;具有更好特点&#xff0c;如降低耦…

如何查看下载到本地的大模型的具体大小?占了多少存储空间:Llama-3.1-8B下载到本地大概15GB

这里介绍一下tree命令&#xff0c;可以方便的查看文件目录结构和文件大小。 命令行tree的具体使用&#xff0c;请参考笔者的另一篇博客&#xff1a;深入了解 Linux tree 命令及其常用选项&#xff1a;Linux如何显示目录结构和文件大小&#xff0c;一言以蔽之&#xff0c;sudo a…

MySQL线上事故:使用`WHERE`条件`!=xxx`无法查询到NULL数据

前言 在一次 MySQL 的线上查询操作中&#xff0c;因为 ! 的特性导致未能正确查询到为 NULL 的数据&#xff0c;险些引发严重后果。本文将详细解析 NULL 在 SQL 中的行为&#xff0c;如何避免类似问题&#xff0c;并提供实际操作建议。 1. 为什么NULL会查询不到&#xff1f; 在…

4G报警器WT2003H-16S低功耗语音芯片方案开发-实时音频上传

一、引言 在当今社会&#xff0c;安全问题始终是人们关注的重中之重。无论是家庭、企业还是公共场所&#xff0c;都需要一套可靠的安全防护系统来保障人员和财产的安全。随着科技的飞速发展&#xff0c;4G 报警器应运而生&#xff0c;为安全防范领域带来了全新的解决方案。…

U盘格式化工具合集:6个免费的U盘格式化工具

在日常使用中&#xff0c;U盘可能会因为文件系统不兼容、数据损坏或使用需求发生改变而需要进行格式化。一个合适的格式化工具不仅可以清理存储空间&#xff0c;还能解决部分存储问题。本文为大家精选了6款免费的U盘格式化工具&#xff0c;并详细介绍它们的功能、使用方法、优缺…

玩转OCR | 腾讯云智能结构化OCR初次体验

目录 一、什么是OCR&#xff08;需要了解&#xff09; 二、产品概述与核心优势 产品概述 智能结构化能做什么 举例说明&#xff08;选看&#xff09; 1、物流单据识别 2、常见证件识别 3、票据单据识别 4、行业材料识别 三、产品特性 高精度 泛化性 易用性 四、…

基于微信小程序的校园自助打印系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…

driftingblues6_vh靶机

首先把靶机换成NAT模式 使用 arp-scan 命令扫描网段内存活的主机&#xff0c;以获取靶机ip地址 arp-scn -l 尝试访问ip 使用御剑扫描子域名&#xff0c;尝试访问robots.txt文件 通过访问文件我们发现了一个/textpattern/textpattern目录 访问一下目录发现了登录页面 他还给了…

STM32使用UART发送字符串与printf输出重定向

首先我们先看STM32F103C8T6的电路图 由图可知&#xff0c;其PA9和PA10引脚分别为UART的TX和RX(注意&#xff1a;这个电路图是错误的&#xff0c;应该是PA9是X而PA9是RX&#xff0c;我们看下图的官方文件可以看出)&#xff0c;那么接下来我们应该找到该引脚的定义是什么&#xf…

数据库自增 id 过大导致前端时数据丢失

可以看到&#xff0c;前端响应参数是没有丢失精度的 但是在接受 axios 请求参数时出现了精度丢失 解决方案一&#xff1a;改变 axios 字符编码 axios.defaults.headers[Content-Type] application/json;charsetUTF-8; 未解决 解决方案二&#xff1a;手动使用 json.parse() …