Spring Boot - 具有动态添加路径的多个登录页面 - 不支持405'POST'

时间:2017-07-31 18:13:14

标签: java spring spring-mvc spring-boot spring-security

我的Spring Boot应用程序出了问题,我试图实现动态配置的多个登录页面。

在数据库中存储了页面的前缀,我正在尝试获取单独登录页面的多个路径。

我正在尝试在以下SecurityConfig类中执行此操作 ( global.getPath()返回普通前缀String ):

@Configuration
@EnableGlobalMethodSecurity( securedEnabled = true )
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private GlobalSettingsService globalSettingsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        List<GlobalSettings> globals = globalSettingsService.findAll();

        http
                .authorizeRequests()
                    .antMatchers("/css/**", "/index").permitAll()
                    .antMatchers("/js/**", "/").permitAll()
                    .antMatchers("/fonts/**", "/img/**").permitAll();
        for (GlobalSettings global : globals) {
            http.authorizeRequests()
               .antMatchers("/"+global.getPath()+"/**").permitAll()
               .antMatchers("/"+global.getPath()+"/admin/**").hasAnyRole("USER","ADMIN")
                .and()
                .formLogin().loginProcessingUrl("/"+global.getPath()+"/login")
                    .loginPage("/"+global.getPath()+"/login").permitAll()
                    .defaultSuccessUrl("/"+global.getPath()+"/admin")
                .failureUrl("/"+global.getPath()+"/login?error").permitAll()
                .and()
                .logout()
                    .logoutRequestMatcher(new AntPathRequestMatcher("/"+global.getPath()+"/login?logout"))
                    .logoutSuccessUrl("/"+global.getPath()+"/login?logout")
                    .permitAll();
        }
    }
}

登录表单视图在另一个类(WebConfig)中配置,该类扩展了WebMvcConfigureAdapter:

for (GlobalSettings global : globals) {
            registry.addViewController("/"+global.getPath()+"/login").setViewName(global.getPath()+"-/login-form");
        }

我有3个前缀要配置,并且循环中配置的最后一个正常工作(可能是最高顺序?) - 我可以毫无困难地登录和退出。

因此配置仅适用于循环中调用的最后一个前缀。其他前缀正在呈现正确的登录表单,但在登录尝试后返回405代码,并显示以下消息:

o.s.web.servlet.PageNotFound: Request method 'POST' not supported

所以我在我的一个控制器中进行了自定义POST方法定义:

@RequestMapping(value = "/{path}/login", method = RequestMethod.POST)
public ModelAndView getLoginPage(@PathVariable("path") String path, @RequestParam Optional<String> error) {
        return new ModelAndView(path+"-front/login-form", "error", error);
}

但遗憾的是,当登录请求路径正确时,它仍未被识别,仍然收到“方法不受支持”消息。

此外,在应用程序初始化期间路径正确映射,因此我不知道问题出在哪里。 我尝试了很多方法,比如在登录表单中添加隐藏的_csrf字段,但仍然没有任何结果。

是否可以避免前缀硬编码? 它与@Order注释有关吗?

感谢您的时间

1 个答案:

答案 0 :(得分:0)

我通过重建SecurityConfig类来解决它,为每个前缀创建单独的WebSecurityConfigurerAdapters:

@Configuration
@EnableGlobalMethodSecurity( securedEnabled = true )
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;
    @Autowired
    private GlobalSettingsService globalSettingsService;

    @Configuration
    @Order(1)
    public static class FirstPrefixWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/app1/**")
                .authorizeRequests()
                .antMatchers("/app1/**").permitAll()
                .antMatchers("/app1/login").permitAll()
                .antMatchers("/app1/admin/**")
                .hasAnyRole("ADMIN","USER")
                .and()
                .formLogin().loginProcessingUrl("/app1/login")
                .loginPage("/app1/login").permitAll()
                .defaultSuccessUrl("/app1/admin")
                .failureUrl("/app1/login?error").permitAll()
                .and()
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/app1/login?logout"))
                .logoutSuccessUrl("/app1/login?logout")
                .permitAll();

        }
    }
    @Configuration
    @Order(2)
    public static class SecondPrefixWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/app2/**")
                .authorizeRequests()
                .antMatchers("/app2/**").permitAll()
                .antMatchers("/app2/login").permitAll()
                .antMatchers("/app2/admin/**")
                .hasAnyRole("ADMIN","USER")
                .and()
                .formLogin().loginProcessingUrl("/app2/login")
                .loginPage("/app2/login").permitAll()
                .defaultSuccessUrl("/app2/admin")
                .failureUrl("/app2/login?error").permitAll()
                .and()
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/app2/login?logout"))
                .logoutSuccessUrl("/app2/login?logout")
                .permitAll();


        }
    }
    @Configuration
    @Order(3)
    public static class ThirdPrefixWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/app3/**")
                .authorizeRequests()
                .antMatchers("/app3/**").permitAll()
                .antMatchers("/app3/login").permitAll()
                .antMatchers("/app3/admin/**")
                .hasAnyRole("ADMIN","USER")
                .and()
                .formLogin().loginProcessingUrl("/app3/login")
                .loginPage("/app3/login").permitAll()
                .defaultSuccessUrl("/app3/admin")
                .failureUrl("/app3/login?error").permitAll()
                .and()
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/app3/login?logout"))
                .logoutSuccessUrl("/app3/login?logout")
                .permitAll();


        }
    }

}

这不是一个动态的解决方案,但现在也没问题。