Apache Shiro JdbcRealm 与 JavaConfig 和 Spring Boot

2023-11-30

我正在尝试配置我的 Spring Boot 应用程序以使用 Apache Shiro 作为其安全框架。我已经完成了与 PropertiesRealm 一起使用的所有操作,现在我正在尝试使其与 JdbcRealm 和 Spring Boot 的内置 H2 数据库一起使用。这是我的 pom.xml 中的依赖项:

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-web</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>

我的 schema.sql:

create table if not exists users (
  username varchar(256),
  password varchar(256),
  enabled boolean
);

create table if not exists user_roles (
  username varchar(256),
  role_name varchar(256)
);

我的数据.sql:

insert into users (username, password, enabled) values ('user', '04f8996da763b7a969b1028ee3007569eaf3a635486ddab211d512c85b9df8fb', true);

insert into user_roles (username, role_name) values ('user', 'guest');

我的 WebSecurityConfig.java 类配置了所有内容:

package security;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.AnonymousFilter;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.filter.authc.UserFilter;
import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.h2.server.web.WebServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class WebSecurityConfig {

    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter() {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        Map<String, String> filterChainDefinitionMapping = new HashMap<>();
        filterChainDefinitionMapping.put("/api/health", "authc,roles[guest],ssl[8443]");
        filterChainDefinitionMapping.put("/login", "authc");
        filterChainDefinitionMapping.put("/logout", "logout");
        shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMapping);
        shiroFilter.setSecurityManager(securityManager());
        shiroFilter.setLoginUrl("/login");
        Map<String, Filter> filters = new HashMap<>();
        filters.put("anon", new AnonymousFilter());
        filters.put("authc", new FormAuthenticationFilter());
        LogoutFilter logoutFilter = new LogoutFilter();
        logoutFilter.setRedirectUrl("/login?logout");
        filters.put("logout", logoutFilter);
        filters.put("roles", new RolesAuthorizationFilter());
        filters.put("user", new UserFilter());
        shiroFilter.setFilters(filters);
        return shiroFilter;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(jdbcRealm());
        return securityManager;
    }

    @Autowired
    private DataSource dataSource;

    @Bean(name = "realm")
    @DependsOn("lifecycleBeanPostProcessor")
    public JdbcRealm jdbcRealm() {
        JdbcRealm realm = new JdbcRealm();
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
        realm.setCredentialsMatcher(credentialsMatcher);
        realm.setDataSource(dataSource);
        realm.init();
        return realm;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public ServletRegistrationBean h2servletRegistration() {
        ServletRegistrationBean registration = new ServletRegistrationBean(new WebServlet());
        registration.addUrlMappings("/console/*");
        return registration;
    }
}

我在日志中没有看到任何错误。我尝试将以下内容添加到我的 application.properties 中来启动日志记录,但这没有多大帮助。

logging.level.org.apache.shiro=debug

Thanks,

Matt


正在发生一些问题。

生命周期 BeanPostProcessor

问题是由于这样的事实LifecycleBeanPostProcessor在您的配置类中定义。既然它是一个BeanPostProcessor它必须立即初始化才能处理所有其他 bean。此外,其余的WebSecurityConfig需要立即初始化,因为它可能会影响LifecycleBeanPostProcessor.

问题是自动装配功能尚不可用,因为它是BeanPostProcessor (i.e. AutowiredAnnotationBeanPostProcessor) 也。这意味着DataSource一片空白。

由于它为空JdbcRealm将要抛出一个NullPointerException。这依次是被抓住AbstractAuthenticator and 被重新抛出AuthenticationException. The DefaultWebSecurityManager(实际上它的父级DefaultSecurityManager)然后抓住它invokes onFailedLogin这会删除“记住我”cookie。

解决BeanPostProcessor生命周期

最简单的解决方案是确保使用静态方法定义任何与基础设施相关的 bean。这通知 Spring 它不需要初始化整个配置类(即WebSecurityConfig). Again

@Bean
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
    return new LifecycleBeanPostProcessor();
}

或者,您也可以在其自己的配置中隔离基础设施相关的 Bean。

UPDATE

ShiroFilterFactoryBean

我没有意识到ShiroFilterFactoryBean实施BeanPostProcessor还。这是一个非常有趣的案例ObjectFactory还实施BeanPostProcessor.

问题是,这会阻止加载 data.sql,这意味着应用程序表中没有任何用户,因此身份验证将失败。

问题是 data.sql 是通过DataSourceInitializedEvent。然而,由于急于初始化DataSource(这是一个依赖项BeanPostProcessor) the DataSourceInitializedEvent不能被解雇。这就是您在日志中看到以下内容的原因:

无法发送事件以完成数据源初始化(ApplicationEventMulticaster 未初始化)

确保 data.sql 加载

我看到有几个选项可以加载插入语句。

数据.sql->模式.sql

最简单的选择是将 data.sql 的内容移动到 schema.sql。 schema.sql 仍会加载,因为它不需要触发事件来处理它。 data.sql 需要一个事件,以便在 JPA 初始化架构时可以使用相同的机制来加载数据。

修复排序

不幸的是,你不能简单地定义ShiroFilterFactoryBean静态的,因为它依赖于其他 bean 定义。幸运的是,确实没有必要BeanPostProcessor在这种情况下。这意味着您可以更改代码以返回工厂 bean 的结果,从而删除BeanPostProcessor由等式可知:

@Bean(name = "shiroFilter")
public AbstractShiroFilter shiroFilter() throws Exception {
    ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
    Map<String, String> filterChainDefinitionMapping = new HashMap<>();
    filterChainDefinitionMapping.put("/api/health", "authc,roles[guest],ssl[8443]");
    filterChainDefinitionMapping.put("/login", "authc");
    filterChainDefinitionMapping.put("/logout", "logout");
    shiroFilter.setFilterChainDefinitionMap(filterChainDefinitionMapping);
    shiroFilter.setSecurityManager(securityManager());
    shiroFilter.setLoginUrl("/login");
    Map<String, Filter> filters = new HashMap<>();
    filters.put("anon", new AnonymousFilter());
    filters.put("authc", new FormAuthenticationFilter());
    LogoutFilter logoutFilter = new LogoutFilter();
    logoutFilter.setRedirectUrl("/login?logout");
    filters.put("logout", logoutFilter);
    filters.put("roles", new RolesAuthorizationFilter());
    filters.put("user", new UserFilter());
    shiroFilter.setFilters(filters);
    return (AbstractShiroFilter) shiroFilter.getObject();
}

插入用户

data.sql中发现insert语句不正确。它需要包括enabled柱子。例如:

insert into users values ('admin', '22f256eca1f336a97eef2b260773cb0d81d900c208ff26e94410d292d605fed8',true);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Apache Shiro JdbcRealm 与 JavaConfig 和 Spring Boot 的相关文章

  • 在不支持 CAS 操作的处理器上进行 CompareAndSet

    今天 我在一次采访中被问到下一个问题 如果您在具有不支持 CAS 操作的处理器的机器上调用 AtomicLong 的compareAndSet 方法 会发生什么情况 您能否帮我解决这个问题 并在可能的情况下提供一些全面描述的链接 From
  • 有人用过 ServiceLoader 和 Guice 一起使用吗?

    我一直想通过我们的应用程序 构建系统进行更大规模的尝试 但更高的优先级不断将其推到次要地位 这似乎是加载 Guice 模块的好方法 并且避免了关于 硬编码配置 的常见抱怨 单个配置属性很少会自行更改 但您几乎总是会有一组配置文件 通常用于不
  • 什么是内部类的合成反向引用

    我正在寻找应用程序中的内存泄漏 我正在使用的探查器告诉我寻找这些类型的引用 但我不知道我在寻找什么 有人可以解释一下吗 Thanks Elliott 您可以对 OUTER 类进行合成反向引用 但不能对内部类实例进行合成 e g class
  • 自定义列表字段点击事件

    我正在编写一个应用程序 其中我创建了用于显示列表视图的自定义列表字段 我的 CustomListField 包含连续的一个图像和文本 我正在通过单击列表字段行获取字段更改侦听器 但我也想将字段更改侦听器放在图像上 谁能告诉我我该怎么做 这是
  • 如何更改 Swagger-ui URL 前缀?

    我正在使用 Springfox Swagger2 和 Spring boot 1 5 9 我可以通过此链接访问 swagger UI http localhost 8090 swagger ui html http localhost 80
  • 如何在 IntelliJ IDEA 中运行 akka actor

    来自 Akka 网站文档 然后 这个主要方法将创建所需的基础设施 运行演员 启动给定的主要演员并安排 一旦主要参与者终止 整个应用程序就会关闭 因此 您将能够使用类似于以下的命令运行上面的代码 下列的 java classpath akka
  • 使用 Proguard 通过 Dropbox.com 库混淆 Android 应用程序

    我刚刚创建了一个需要 Dropbox com API 库的 Android 应用程序 我现在尝试在 发布 模式下构建应用程序 并希望在代码上运行混淆器以对其进行混淆 但是 每当我尝试运行 Proguard 时 都会收到以下错误 Progua
  • 类更改(例如字段添加或删除)是否保持 Serialized 的向后兼容性?

    我有一个关于 Java 序列化的问题 在这种情况下 您可能需要修改可序列化类并保持向后兼容性 我有丰富的 C 经验 所以请允许我将 Java 与 NET 进行比较 在我的Java场景中 我需要使用Java的运行时序列化机制序列化一个对象 并
  • Android - 存储对ApplicationContext的引用

    我有一个静态 Preferences 类 其中包含一些应用程序首选项和类似的内容 可以在那里存储对 ApplicationContext 的引用吗 我需要该引用 以便我可以在不继承 Activity 的类中获取缓存文件夹和类似内容 你使用的
  • Java 8 Stream,获取头部和尾部

    Java 8 引入了Stream http download java net jdk8 docs api java util stream Stream html类似于 Scala 的类Stream http www scala lang
  • 如何使用 Jersey 将嵌套列表封送为 JSON?我得到一个空数组或一个包含数组的单元素字典数组

    我正在开发一个使用 Jersey 将对象转换为 JSON 的项目 我希望能够写出嵌套列表 如下所示 data one two three a b c 我想要转换的对象首先将数据表示为 gt gt 我认为 Jersey 会做正确的事情 以上输
  • Tomcat 6 未从 WEB-INF/lib 加载 jar

    我正在尝试找出我的 tomcat 环境中的配置问题 我们的生产服务器正在运行 tomcat 安装并从共享 NFS 挂载读取战争 然而 当我尝试使用独立的盒子 及其配置 进行同样的战争时 我收到下面发布的错误 有趣的是 如果我将 WEB IN
  • 文本视图不显示全文

    我正在使用 TableLayout 和 TableRow 创建一个简单的布局 其中包含两个 TextView 这是代码的一部分
  • Azure Java SDK:ServiceException:ForbiddenError:

    尝试了基本位置检索器代码 如下所示 String uri https management core windows net String subscriptionId XXXXXXXX 5fad XXXXXX 9dfa XXXXXX St
  • 确定 JavaFX 中是否消耗了事件

    我正在尝试使用 JavaFX 中的事件处理来做一些非滑雪道的事情 我需要能够确定手动触发事件后是否已消耗该事件 在以下示例中 正确接收了合成鼠标事件 但调用 Consumer 不会更新该事件 我对此进行了调试 发现 JavaFX 实际上创建
  • 如何让 Firebase 与 Java 后端配合使用

    首先 如果这个问题过于抽象或不适合本网站 我想表示歉意 我真的不知道还能去哪里问 目前我已经在 iOS 和 Android 上开发了应用程序 他们将所有状态保存在 Firebase 中 因此所有内容都会立即保存到 Firebase 实时数据
  • 使用 DBCP 配置 Tomcat

    在闲置一段时间 几个小时 后 我们收到了 CommunicationsException 来自 DBCP 错误消息 在异常中 位于这个问题的末尾 但我没有看到任何配置文件中定义的 wait timeout 我们应该看哪里 在 tomcat
  • Java 的“&&”与“&”运算符

    我使用的示例来自 Java Herbert Schildt 的完整参考文献 第 12 版 Java 是 14 他给出了以下 2 个示例 如果阻止 第一个是好的 第二个是错误的 因此发表评论 public class PatternMatch
  • Spring 作为 JNDI 提供者?

    我想使用 Spring 作为 JNDI 提供程序 这意味着我想在 Spring 上下文中配置一个 bean 可以通过 JNDI 访问该 bean 这看起来像这样
  • 设置 TreeSet 的大小

    有没有办法像数组一样对 Java 集合中的 TreeSet 进行大小限制 例如我们在数组中 anArray new int 10 数组具有固定长度 在创建数组时必须指定该长度 A TreeSet当您向其中添加元素时会自动增长 您无法设置其大

随机推荐

  • 修复了滚动项目时导航抽屉中的导航标题

    当前状态 具有 NavigationHeader 和 NavigationMenu 项的 NavigationDrawer 这些项目数量很大 因此需要滚动才能访问底部的项目 要求 向下滚动到底部时 导航标题应保持固定 这是我的 Activi
  • Flutter:英雄过渡+小部件动画同时进行?

    因此 我对 Flutter 的特定动画案例有一些疑问 基本上 我想做的是同时运行用于路线更改的英雄过渡和相邻小部件上的自定义动画 具体来说 我的根目录中有一个自定义的 InheritedWidget 它从 StatefulWidget 父级
  • 获取 XMPP 聊天历史记录 OpenFire

    我正在尝试使用 iOS 中的 XMPPFramework 和 OpenFire 服务器来实现聊天应用程序 我的聊天工作正常 我正在尝试从服务器检索聊天历史记录 当然 我已经在服务器上启用了邮件存档 这是我发送的请求
  • 如何在 Objective-C 中保持会话?

    所以我遇到了以下问题 我有一个登录视图控制器和一个表单视图控制器 在登录视图控制器上 我向 PHP 脚本发送 POST 请求 该脚本验证用户是否具有访问权限 该脚本仅返回 1 或 0 因此我可以选择关闭或维护视图控制器 当凭据正确传递时 用
  • C# 中的对象指针(object*)

    我想要做的是 我想传递一个指向函数的指针 该函数可以是任何类型的变量 int long string 甚至是一个类 我的意思是我应该能够传递任何变量的指针 我就是这样做的 unsafe class whatever whatever obj
  • 声明原子指针与原子指针

    据我所知 以下声明创建了一个值数组 每个值都是原子的 Atomic int x 10 但是 我不清楚这是否 Atomic int x x calloc 10 sizeof int 创建一个包含 10 个原子整数的数组 或者是指向非原子整数数
  • 计算文本的正确宽度

    我需要阅读由 AutoCAD 导出为 PDF 的计划 并使用 PDFBox 在其上放置一些带有文本的标记 除了计算写在标记旁边的文本宽度之外 一切正常 我浏览了整个 PDF 规范并详细阅读了涉及图形和文本的部分 但无济于事 据我了解 字形坐
  • Mac OS 10.16 链接 Homebrew 安装的库

    我已经使用自制程序很长时间了 从未遇到过这个奇怪的问题 由于某种原因 我不会在这里解释我使用的是 MacOS 10 16 Big Sur 这是最新 MacOS 的 Beta 版本 并且已经使用自制软件安装了库 其中一个图书馆是zlib 但是
  • XPath max 函数和括号的使用

    假设我们有以下 XML
  • 无法找出注册表中的 ActiveRecord::SubclassNotFound#edit?

    当处于 编辑 或 显示 状态时 会出现以下情况 ActiveRecord SubclassNotFound 在注册表中 edit 单表继承机制无法定位子类 Plane 出现此错误是因为列 type 被保留用于在继承时存储类 如果您不希望这样
  • 为什么他们在 Mongoose Population 示例中使用 ObjectId 和 Number?

    In this例如 他们创建personSchema using ObjectId来参考Story我明白这一点 但随后在storySchema他们为什么不做同样的事情来引用这个人呢 或者反过来 为什么在 Person 中使用 ObjectI
  • 获取表的列名并将它们存储在字符串或var中c#asp.net

    我想知道如何获取数据库表的列并将它们存储在字符串或字符串数 组中 我有以下代码 但我相信它不起作用 我正在使用 asp net 中给出的默认表 我已经能够毫无问题地写入该表 但我不知道如何从中选择并保存检索到的值 这是我后面的代码中的内容
  • 传递类方法而不是 std::sort 中的函数

    在一个类中 我试图通过传递同一类的方法来对向量进行排序 但是编译的时候会报错 谁能告诉我问题是什么吗 谢谢你 它给出以下错误 类型参数bool Sorter D D does not match书 排序器 D D c 我也尝试过使用sort
  • tao SimpleOpenGlControl 错误

    我正在创建一个包含 Tao Platform Windows SimpleOpenGlControl 的用户控件 在我的控件的构造函数中 我有 InitializeComponent simpleOpenGlControl1 Initial
  • 将 javascript 变量发送到经典 asp

    我有一个基于 jQuery 的成本计算器 我希望网页能够通过电子邮件发送计算 器值的摘要 服务器在经典 ASP 上运行 如何使用 ASP 检索 javascript 变量 据我了解 ASP 代码在页面加载之前运行 而 javascript
  • Python Opencv 和 Sockets - 以 h264 编码的流视频

    所以我正在尝试制作一个流媒体 将视频从局域网上的一台计算机流式传输到另一台计算机 或目前同一台计算机 我需要它使用尽可能少的带宽 所以我尝试用 h264 进行编码 我在做这件事时遇到了困难 我真的不知道从哪里开始 现在它是用jpg编码的 并
  • 计算某个项目在多列中每一列中出现的次数

    我想读取一个表并创建另一个表来计算唯一 ID 在多个特定列中出现的次数 例如 我有一个表 其中每一行显示一个事务 并用一个 userId 标识每个人的角色 buyer lt c A A B A B C seller lt c C B C B
  • 不使用 #define 定义 BIT0、BIT1、BIT2 等

    在C 中是否可以在不使用 define的情况下以另一种方式定义BIT0 BIT1 BIT2 define BIT0 0x00000001 define BIT1 0x00000002 define BIT2 0x00000004 然后我采用
  • 使用 python 编辑 tfvars 文件

    我不知道我问的是否是正确的组 但是有没有办法使用 python 编辑 tfvars 例如 我有一个 tfvars 文件 其中一些变量具有以下值 owner operations port number 80 我想编辑port number
  • Apache Shiro JdbcRealm 与 JavaConfig 和 Spring Boot

    我正在尝试配置我的 Spring Boot 应用程序以使用 Apache Shiro 作为其安全框架 我已经完成了与 PropertiesRealm 一起使用的所有操作 现在我正在尝试使其与 JdbcRealm 和 Spring Boot