shiro 使用自定义过滤器报告错误“调用代码无法访问 SecurityManager”

问题描述 投票:0回答:1

原本我的filterChainDefinitionMap是

filterChainDefinitionMap.put("/login/**","anon");
调用接口时响应正常,但现在我有需求。登录成功后需要记录所有
"/login/**"
。一些信息,所以我自定义了一个CustomLoginFilter并继承自BasicHttpAuthenticationFilter,重写了onLoginSuccess方法。然后将filterChainDefinitionMap改为
filterChainDefinitionMap.put("/login/**", "customLoginFilter");
,此时发现接口调用的返回值为
{"timestamp":1713163170942,"status":500,"error":"Internal Server Error","path":"/login/local"}
。查看控制台后,发现错误信息为
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton.  This is an invalid application configuration.

不知道我的shiro配置是否错误。网上查了资料,其中一种方法是手动将securityManage绑定到当前线程,即

ThreadContext.bind(securityManager);
此时发现接口调用响应的HTTP状态码变成了401,并且没有日志在控制台上生成。

以下是我的shiro配置类。

@Slf4j
@Configuration
public class ShiroConfig {

    @Value("${spring.data.redis.host}")
    private String host;

    @Value("${spring.data.redis.port}")
    private int port;

    @Value("${redis.biz_cache_time.session}")
    private Long sessionExpireTime;

    @Autowired
    private RedisTemplate<Serializable, Session> redisShiroTemplate;


    @Bean
    public ShiroFilterFactoryBean getShiroFilterBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();

        bean.setSecurityManager(defaultWebSecurityManager);


        LinkedHashMap<String, Filter> filterMap = new LinkedHashMap<>();
        filterMap.put("customLoginFilter",new CustomLoginFilter());
        bean.setFilters(filterMap);


        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/login/**", "customLoginFilter");
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        bean.setLoginUrl("/login/to-login");

        return bean;
    }


    @Bean(name="securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(AbstractAuthenticator abstractAuthenticator){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setSessionManager(sessionManager());
        securityManager.setAuthenticator(abstractAuthenticator);
        return securityManager;
    }


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



    @Bean
    public AbstractAuthenticator abstractAuthenticator() {
        ModularRealmAuthenticator authenticator = new MyCustomModularRealmAuthenticator();
        authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        List<Realm> realms = new ArrayList<>();
        realms.add(customRealm());
        authenticator.setRealms(realms);
        return authenticator;
    }


    @Bean
    public DefaultWebSessionManager sessionManager() {
        StatelessSessionManager sessionManager = new StatelessSessionManager();
        sessionManager.setSessionIdCookie(cookie());
        sessionManager.setGlobalSessionTimeout(sessionExpireTime);
        sessionManager.setSessionDAO(redisSessionDAO());
        sessionManager.setDeleteInvalidSessions(true);
        return sessionManager;
    }

    @Bean
    public CustomRealm customRealm() {
        return new CustomRealm();
    }

    @Bean
    public SimpleCookie cookie() {
        SimpleCookie cookie = new SimpleCookie("Authorization");
        cookie.setPath("/");
        return cookie;
    }


    @Bean
    SessionDAO redisSessionDAO() {
        return new RedisSessionDAO(MagicValueConst.SHIRO_REDIS_PREFIX, sessionExpireTime, redisShiroTemplate);
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
}

我的maven配置如下:

    ...
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    ...
       <properties>
        <java.version>17</java.version>
       </properties>
    ...
            <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.13.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.shiro</groupId>
                    <artifactId>shiro-spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <classifier>jakarta</classifier>
            <version>1.13.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.shiro</groupId>
                    <artifactId>shiro-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.apache.shiro</groupId>
                    <artifactId>shiro-web</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <classifier>jakarta</classifier>
            <version>1.13.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <classifier>jakarta</classifier>
            <version>1.13.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.shiro</groupId>
                    <artifactId>shiro-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

java spring-boot filter shiro
1个回答
0
投票

看起来这里有很多额外的配置。我的建议是“降低复杂性”,直到一切正常。看一下 Shiro 树中的示例:

https://github.com/apache/shiro/blob/f15073b8f7b6bc38af0575f6442885c945b319ab/samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/WebApp.java#L86-L92

我也有点不确定这个问题。您似乎正在扩展

BasicHttpAuthenticationFilter

并设置一个使用 cookie 的无状态会话管理器? 与基本身份验证类似的流程不会从请求特定登录 URL 开始(并且不需要 cookie)。

一般来说,请谨慎覆盖默认配置,因为您可能会绕过一些开箱即用的默认安全设置。

您能否在 GitHub(或类似的地方)上创建一个简单的示例并定义重现此问题的步骤?

© www.soinside.com 2019 - 2024. All rights reserved.