当前位置: 首页 > 知识库问答 >
问题:

在Spring启动中添加Spring Security@EnableGlobal方法安全时,需要ServletContext来配置默认servlet处理错误

洪飞龙
2023-03-14

我正在将Spring MVC servlet 3.1应用程序移动到Spring Boot 1.3.0,当我将@EnableGlobalMethodSecurity注释添加到我的一个Java配置类时,我在启动时出现异常(完整如下)。

我正在为我的Spring安全支持子类化WebSecurityCon

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityAuthorisationConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http.csrf()...

即使在类中没有其他依赖项@Autowired,启动也会失败。如果删除@EnableGlobalMethodSecurity注释,启动将成功,但显然没有方法安全性。大多数其他web安全SO帖子似乎是由于安全配置无法在分派器servlet之前启动,但由于我的安全配置中没有其他依赖项,我无法理解为什么会发生这种情况。

我尝试了很多方法来启动应用程序,并更改了安全配置的@Order,但都没有用。

我当前的应用程序切入点看起来像这样,尽管我也尝试过使用自动魔法调度程序初始化,我也遇到了同样的问题:

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = { "com.myapp.config.web", "com.myapp.config.app" })
public class Application extends SpringBootServletInitializer {
        private static Class<Application> applicationClass = Application.class;

        public static void main(final String[] args) throws Exception {
            SpringApplication.run(applicationClass, args);
        }

        @Autowired
        private AuditLogger auditLogger;

        @Override
        public void onStartup(final ServletContext container) throws ServletException {
            final AnnotationConfigWebApplicationContext rootContext = createRootContext(container);

            setUpSessionConfig(container);

            setUpMdcLoggingFilter(container);

            setAllUndefinedRequestsToUtf8(container);

            setUpAuditLogging(container);

            addSecurityFilter(container);

            addUpdateExpiredPasswordFilter(container);

            createDispatcher(container, rootContext);
        }

        private void setUpSessionConfig(final ServletContext container) {
            container.getSessionCookieConfig().setHttpOnly(true);
            container.setSessionTrackingModes(asSet(SessionTrackingMode.COOKIE));
        }

        private void setUpMdcLoggingFilter(final ServletContext container) {
            final Dynamic mdcFilter = container.addFilter("mdcInsertingFilter",
                    new DelegatingFilterProxy(mdcInsertingFilter()));
            mdcFilter.addMappingForUrlPatterns(null, true, "/*");
        }

        private void addUpdateExpiredPasswordFilter(final ServletContext container) {
            final Dynamic filter = container.addFilter("updateExpiredPasswordFilter",
                    new DelegatingFilterProxy(updateExpiredPasswordFilter()));
            filter.addMappingForUrlPatterns(null, true, "/*");
        }

        private void setUpAuditLogging(final ServletContext container) {
            final Dynamic auditLoggingFilter = container.addFilter("auditLogFilter",
                    new DelegatingFilterProxy(auditLogFilter()));
            auditLoggingFilter.addMappingForUrlPatterns(null, true, "/*");

        }

        private void addSecurityFilter(final ServletContext container) {
            final Dynamic securityFilter =
                    container.addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME,
                            DelegatingFilterProxy.class);
            securityFilter.addMappingForUrlPatterns(null, true, "/*");
        }

        private AnnotationConfigWebApplicationContext createRootContext(final ServletContext servletContext) {
            final AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
            rootContext.register(AppConfig.class);
            rootContext.setServletContext(servletContext);

            servletContext.addListener(new ContextLoaderListener(rootContext));
            servletContext.setInitParameter("spring.profiles.default", "production");
            return rootContext;
        }

        private void setAllUndefinedRequestsToUtf8(final ServletContext container) {
            final FilterRegistration filter = container.addFilter("encodingFilter", OrderedCharacterEncodingFilter.class);
            filter.setInitParameter("encoding", "UTF-8");
            filter.addMappingForUrlPatterns(null, true, "/*");
        }

        private void createDispatcher(final ServletContext container,
                final AnnotationConfigWebApplicationContext rootContext) {
            final DispatcherServlet dispatcherServlet = new DispatcherServlet(rootContext);
            final ServletRegistration.Dynamic dispatcher =
                    container.addServlet("myServlet", dispatcherServlet);

            dispatcher.setLoadOnStartup(1);
            dispatcher.addMapping("/");
        }

        @Bean
        public AuditLogFilter auditLogFilter() {
            final AuditLogFilter auditLogFilter = new AuditLogFilter();
            auditLogFilter.setAuditLogger(auditLogger);
            auditLogFilter.setIgnoredPaths("/resources,/webjars");
            return auditLogFilter;
        }

        @Bean
        public UpdateExpiredPasswordFilter updateExpiredPasswordFilter() {
            final UpdateExpiredPasswordFilter filter = new UpdateExpiredPasswordFilter();
            filter.setPasswordUpdateFormPath("/user/change_password");
            filter.setPasswordUpdatePath("user/change_password");
            filter.setLogoutPath("/logout");
            filter.setIgnoredPaths("/resources,/webjars");
            return filter;
        }

        @Bean(name = "mdcInsertingFilter")
        public MDCInsertingServletFilter mdcInsertingFilter() {
            return new MDCInsertingServletFilter();
        }
}

虽然我不一定期望得到一个全面的解决方案,但知道从哪里开始寻找问题的原因将非常有用。这是bug吗?这可能与我创建应用程序的方式有关吗?

堆栈跟踪:


共有1个答案

邬阳
2023-03-14

通过将@ EnableGlobalMethodSecurity(prePostEnabled = true)注释从WebSecurityConfigurerAdapter实现移动到它自己的config类,并扩展GlobalMethodSecurityConfiguration来配置身份验证管理器,我终于成功地实现了这一点。

我有一种感觉,这是一个变通的解决方案,但至少它是固定的。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Override
    public void configure(final AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setPasswordEncoder(new StandardPasswordEncoder());
        authProvider.setUserDetailsService(userDetailsService());
        return authProvider;
    }

    @Bean
    public MyUserDetailsService userDetailsService() {
        return new MyUserDetailsService(...);
    }

}
 类似资料:
  • 当我将messageSource方法重命名为messageSource2时,它可以工作,但我不太会使用自带默认messageSource的LocalizedMessageService来查询自定义消息。 如何将自定义消息基名称添加到默认消息源?

  • 问题内容: 我有以下测试课: 问题似乎来自BaseTestConfiguration类: 我系统地得到了这个异常: 我不确定如何解决此问题。当我运行测试时,Spring不知何故正在寻找ServletContext并收到上述异常… 问题答案: 你的其中一门课程显然带有注释。这是如何结束在你的堆栈跟踪,因为它是进口的。 因此,尽管你认为自己不需要(因此也不需要),但实际上确实需要它,只是因为你正在使用

  • 我试图使用Spring Boot与嵌入式。我希望嵌入式码头打开一个HTTPS端口443。

  • 我为spring-boot创建了一个spring安全配置类。我的登录页面有资源css、js和ico文件。这些资源由于安全原因而被拒绝,并且每次都被重定向到登录页面。为什么EnableWebMVCSecurity不添加类路径资源位置。在更改代码后,如第二个代码片段所示,将添加I Classpath资源位置。不明白第一段代码中的资源缺少什么。 我通过将代码更改为 在更改代码之后,我注意到忽略路径被添加

  • 我正在开发一个被其他项目使用的库。该库通过JDBC提供数据库访问,我想在同一个库中也添加对R2DBC的支持。使用项目应该能够根据配置属性在JDBC和R2DBC之间切换。 我面临的问题是(2.5.4)提供的R2DBC自动配置覆盖了JDBC配置,并且使用的项目只能使用R2DBC。 此外,在构建项目时,有些任务,如留档或代码生成、测试等,取决于正在加载的Spring上下文,但不需要数据库访问。这些任务失

  • Spring Boot是否有默认的EntityManager。我现在正在设置一个,但我注意到当我的项目加载时,我看到了以下内容: LocalContainerEntityManagerFactoryBean:为持久性单元“默认”构建JPA容器EntityManagerFactory 这是默认的EntityManager吗?如果是,我如何访问它? 提前谢谢你。