在 Spring Boot 2 中集成 JCasbin 并实现 ClassPath 模型文件加载
在 Spring Boot 2 中集成 JCasbin 并实现 ClassPath 模型文件加载
概述
在现代Web应用开发中,权限管理和认证是不可或缺的一部分。JCasbin 是一个强大的、高效的开源访问控制库,它支持多种访问控制模型,并提供了灵活的策略管理机制。本文将介绍如何在 Spring Boot 2 应用程序中集成 JCasbin,并解决加载 classpath 中 model.conf 文件的问题。我们还将探讨 classpath: 和 classpath*: 的异同,以及如何正确地使用它们。
集成步骤
添加依赖
首先,在项目的 pom.xml 文件中添加 JCasbin 的相关依赖:
<!-- https://mvnrepository.com/artifact/org.casbin/jcasbin -->
<dependency>
    <groupId>org.casbin</groupId>
    <artifactId>jcasbin</artifactId>
    <version>1.78.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.casbin/mybatis-adapter -->
<dependency>
    <groupId>org.casbin</groupId>
    <artifactId>jdbc-adapter</artifactId>
    <version>2.10.0</version>
</dependency>
修改 Config 类以支持 ClassPath 加载
为了解决 JCasbin 的 Config 类默认不支持从 Java ClassPath 加载模型配置文件的问题,我们对 org.casbin.jcasbin.config.Config 类进行重写,修改了 parse 方法,使其能够首先尝试从 ClassPath 加载模型文件,如果失败,则回退到文件系统路径。以下是修改后的 parse 方法代码片段:
private void parse(String fname) {
    lock.lock();
    try {
        // 尝试从classpath加载资源
        InputStream is = this.getClass().getResourceAsStream(fname);
        if (is == null) {
            // 如果classpath中没有,则尝试从文件系统加载
            try {
                is = new FileInputStream(fname);
            } catch (Exception e) {
                throw new CasbinConfigException("无法找到文件: " + fname, e.getCause());
            }
        }
        BufferedReader buf = new BufferedReader(new InputStreamReader(is));
        parseBuffer(buf);
        // 确保关闭流
        buf.close();
        is.close();
    } catch (IOException e) {
        throw new CasbinConfigException(e.getMessage(), e.getCause());
    } finally {
        lock.unlock();
    }
}
配置 Casbin
接下来,创建一个配置类来初始化 JCasbin 的 Enforcer 实例,该实例会读取权限规则并执行权限检查。:
@Configuration
public class CasbinConfiguration {
    @Bean
    public Enforcer enforcer(CasbinProperties properties, DataSource dataSource) throws Exception {
        JDBCAdapter adapter = new JDBCAdapter(dataSource);
        CustomConfig config = new CustomConfig();
        config.loadModelFromText(Files.readString(Paths.get(properties.getModelPath())));
        Enforcer enforcer = new Enforcer(config, adapter);
        enforcer.loadPolicy();
        return enforcer;
    }
}
请注意,上面的代码片段假设 properties.getModelPath() 返回的是一个可以直接读取文本的文件路径或 ClassPath 资源路径。根据实际情况,可能需要调整这段代码。dataSource使用系统的数据源
处理 ClassPath 资源路径
为了正确加载位于 classpath 下的 model.conf 文件,我们需要理解 classpath: 和 classpath*: 之间的差异。getResourceAsStream() 方法是 Java 原生方法,不支持 classpath*: 语法,这是 Spring 框架特有的功能,用于扫描所有 classpath 下的资源,包括从多个 jar 文件中查找资源。
因此,当您需要通过 Java 原生方法加载资源时,请确保只使用 classpath: 或者直接指定文件路径。对于 Spring 框架提供的工具类,如 ResourceLoader,可以使用 classpath*: 来尝试加载所有匹配的资源。
创建自定义属性类
定义一个配置属性类来接收和设置 application.properties 或 application.yml 中的相关配置。
@Configuration
@ConfigurationProperties(prefix = "casbin")
@Data
public class CasbinProperties {
    private String modelPath;
}
实现过滤器进行权限校验
创建一个过滤器,在每次请求到达时,根据用户信息、请求路径和 HTTP 方法调用 Enforcer 进行权限验证。
@Component
@WebFilter(urlPatterns = "/*")
@Order(1)
public class CasbinAuthFilter implements Filter {
    private final Enforcer enforcer;
    public CasbinAuthFilter(Enforcer enforcer) {
        this.enforcer = enforcer;
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        UserAccountVo userAccountVo = WebUtil.getCurUserAccountVo(httpRequest);
        if (userAccountVo == null){
            chain.doFilter(request, response);
            return;
        }
        String user = userAccountVo.getUserId(); // 从请求头获取用户信息
        String path = httpRequest.getRequestURI();
        String method = httpRequest.getMethod();
        // 进行权限校验
        if (enforcer.enforce(user, path, method)) {
            chain.doFilter(request, response);
        } else {
            httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
            httpResponse.getWriter().write("没有访问权限");
        }
    }
}
model.conf配置示例
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act)
CASBIN_RULE表示例
id,ptype,v0,v1,v2
1,p,1,/*,(GET)|(POST)
结论
通过上述步骤,我们成功地在 Spring Boot 2 应用中集成了 JCasbin,并解决了 model.conf 文件的加载问题。同时,我们也了解了 classpath: 和 classpath*: 之间的区别,并掌握了如何正确地在不同场景下使用它们。这对于任何希望在其应用程序中实现细粒度访问控制的开发者来说都是有价值的知识点。此外,通过重写 Config 类中的 parse 方法,我们实现了更加灵活的模型文件加载机制,使得应用程序更易于部署,特别是在打包为 JAR 文件后部署的情况下。
在 Spring Boot 2 中集成 JCasbin 并实现 ClassPath 模型文件加载的更多相关文章
- Spring Boot 学习系列(09)—自定义Bean的顺序加载
		此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Bean 的顺序加载 有些场景中,我们希望编写的Bean能够按照指定的顺序进行加载.比如,有UserServ ... 
- 如何在Spring Boot项目中集成微信支付V3
		Payment Spring Boot 是微信支付V3的Java实现,仅仅依赖Spring内置的一些类库.配置简单方便,可以让开发者快速为Spring Boot应用接入微信支付. 演示例子: paym ... 
- spring boot入门笔记(四) - 多环境配置、加载顺序、静态资源映射
		1.多环境配置 先描述下以前的开发流程:从SVN把项目下载到本地,各种修改配置文件,启动成功:完成功能后上传到公司的测试服务器,修改各种配置文件,启动成功:最后到上线的日子里,把新功能中涉及到的文件打 ... 
- Spring Boot GraphQL 实战 03_分页、全局异常处理和异步加载
		hello,大家好,我是小黑,又和大家见面啦~ 今天我们来继续学习 Spring Boot GraphQL 实战,我们使用的框架是 https://github.com/graphql-java-ki ... 
- Spring Cloud Alibaba基础教程:Nacos配置的多文件加载与共享配置
		前情回顾: <Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现> <Spring Cloud Alibaba基础教程:支持的几种服务消费方式> ... 
- WPF 中的 Pack URI地(资源文件加载)
		参考资源网http://msdn.microsoft.com/zh-cn/library/aa970069.aspx#Absolute_vs_Relative_Pack_URIs 在 Windows ... 
- Spring Boot - Font Awesome OTS parsing error: Failed to convert  字体加载失败
		字体文件,加载不出来 解决方案 一 问题是Maven正在过滤字体文件并破坏它们. <resource> <directory>${project.basedir}/src/m ... 
- spring boot rest 接口集成 spring security(2) - JWT配置
		Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ... 
- spring boot rest 接口集成 spring security(1) - 最简配置
		Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ... 
- 在Spring Boot项目中使用Spock框架
		转载:https://www.jianshu.com/p/f1e354d382cd Spock框架是基于Groovy语言的测试框架,Groovy与Java具备良好的互操作性,因此可以在Spring B ... 
随机推荐
- C# 深度学习框架 TorchSharp 原生训练模型和图像识别-自定义网络模型和识别手写数字
			目录 使用 Torch 训练模型 定义神经网络 加载数据集 创建网络模型 定义损失函数 训练 识别手写图像 教程名称:使用 C# 入门深度学习 作者:痴者工良 教程地址:https://torch.w ... 
- 闲话 6.19/CF1938M
			CF1938M 计数以下序列 \(\lang a\rang\) 的个数: \[\sum_{i=1}^m a_i=n\\ \forall 1<i<m,(a_i-a_{i-1})(a_i-a_ ... 
- 鸿蒙开发 - 数据持久化 Preferences (内存存储) (封装)
			这篇文章介绍鸿蒙中的 Preferences,它是一种轻量级存储方式,数据存储在内存中,用于存储少量的数据. 可以执行 flush() 方法将内存中的数据写入到磁盘文件,保证下次重启后数据可以继续使用 ... 
- 20 分钟高效掌握 cursor
			本身属于在前端小组的一次小分享,这里做个同步分享. 一.pro 权益说明 目前公司购买了 2 个 pro 月付账号,权益包括无限制 tab 补全与 ai 聊天,但每个月只有 500 个快速请求权益,如 ... 
- C语言编程技巧 全局变量在多个c文件中公用的方法
			在使用C语言编写程序时,经常会遇到这样的情况:我们希望在头文件中定义一个全局变量,并将其包含在两个不同的C文件中,以便这个全局变量可以在这两个文件中共享.举个例子,假设项目文件夹"proje ... 
- docker - [11] 数据卷之DockerFile
			通过DockerFile可以生成一个镜像 一.DockerFile的介绍 狂神:dockerfile是用来构建docker镜像的文件命令参数脚本. 狂神:dockerfile是面向开发的,我们以后要发 ... 
- C/C++跨平台开发1-windows和linux中的类库
			基本概念: 什么是库: 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 静态库:在程序链接的时候使用,链接器会将程序中使 ... 
- 添加xxx.so到环境变量里
			点击查看代码 libxxx.so 文件位于 /usr/local/lib 目录下,你可以按照以下步骤操作: 创建配置文件: echo "/usr/local/lib" | sudo ... 
- js 时间转时间戳
			前言 有时候我们用时间插件,选择好时间后,需要把日期格式转化为时间戳,再传到后台 时间转时间戳 let time = Math.floor(new Date("2014-04-23 18:5 ... 
- IvorySQL v4 逻辑复制槽同步功能解析:高可用场景下的数据连续性保障
			功能简介 IvorySQL v4 基于 PostgreSQL 17,引入了逻辑复制槽同步至热备份数据库的功能.这一改进有效解决了旧版本中主数据库与备份数据库切换后逻辑复制中断的问题.对于那些追求数据高 ... 
