【问题标题】:spring security mapping for wildcards通配符的弹簧安全映射
【发布时间】:2015-10-09 16:51:23
【问题描述】:

使用 Spring-Boot 1.1.17, Spring-MVCSpring-Security:

我希望允许未经身份验证的用户(访问者)访问多个子域。例如:

  • mysite.com/customerA
  • mysite.com/customerB

如果尝试了无效的客户站点,那么我的控制器将抛出异常或重定向回 / (mysite.com/) 自然域的其他部分 (mysite.com/customerA/myaccount) 将需要登录。

我还没有真正弄清楚如何使用 spring security 和 spring-mvc 来做到这一点。到目前为止,这是我正在尝试的:

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterAfter(new CSRFTokenGeneratorFilter(), CsrfFilter.class)
                .authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers( "/**/" ).permitAll()
                .antMatchers("/login").permitAll()
                .antMatchers("/wizard").permitAll()
                .antMatchers("/menu").permitAll()
                .antMatchers("/error").permitAll()
                .antMatchers("/resources/**").permitAll()
                .antMatchers("/css/**").permitAll()
                .antMatchers("/js/**").permitAll()
                .antMatchers("/fonts/**").permitAll()
                .antMatchers("/libs/**").permitAll();

        http
                .formLogin()
                .loginPage("/loginPage")
                .permitAll()
                .loginProcessingUrl("/login")
                .failureUrl("/login?error")
                .defaultSuccessUrl("/?tab=success")
                .and()
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
                .permitAll()
                .and()
                .csrf();

        http
                .sessionManagement()
                .maximumSessions(1)
                .expiredUrl("/login?expired")
                .maxSessionsPreventsLogin(true)
                .and()
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .invalidSessionUrl("/");

        http
                .authorizeRequests().anyRequest().authenticated();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        auth.userDetailsService( customUserDetailsService ).passwordEncoder( encoder );
    }

    @Override
    public void configure(WebSecurity security){
        security.ignoring().antMatchers("/css/**","/fonts/**","/libs/**");
    }
}

还有我的主页控制器:

@Controller
@RequestMapping("/{officeName}/")
public class HomeController {
private AuthenticatedUser getVisitor(@PathVariable String officeName) {

.. do something with the office if found, redirect otherwise
         if (!StringUtils.isEmpty(officeName)) {
            Office office = officeService.findByName( officeName );
            return office.getUrl();

        }
        return "/";
}

当我尝试访问该网址时,我收到以下错误:

 o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/customerA/]
 s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /customerA/
 s.w.s.m.m.a.RequestMappingHandlerMapping : Did not find handler method for [/customerA/]
 o.s.w.s.handler.SimpleUrlHandlerMapping  : Matching patterns for request [/customerA/] are [/**]
 o.s.w.s.handler.SimpleUrlHandlerMapping  : URI Template variables for request [/customerA/] are {}
 o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapping [/customerA/] to HandlerExecutionChain with handler [org.springframework.web.servlet.resource.ResourceHttpRequestHandler@2f295527] and 1 interceptor
 o.s.web.servlet.DispatcherServlet        : Last-Modified value for [/customerA/] is: -1
 o.s.w.s.r.ResourceHttpRequestHandler     : Trying relative path [customerA] against base location: ServletContext resource [/]
 o.s.w.s.r.ResourceHttpRequestHandler     : Trying relative path [customerA] against base location: class path resource [META-INF/resources/]
 o.s.w.s.r.ResourceHttpRequestHandler     : Trying relative path [customerA] against base location: class path resource [resources/]
 o.s.w.s.r.ResourceHttpRequestHandler     : Trying relative path [customerA] against base location: class path resource [static/]
 o.s.w.s.r.ResourceHttpRequestHandler     : Trying relative path [customerA] against base location: class path resource [public/]
 o.s.w.s.r.ResourceHttpRequestHandler     : No matching resource found - returning 404 

我尝试添加这个 ServletRegistrationBean:

@Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
    ServletRegistrationBean registration = new ServletRegistrationBean( dispatcherServlet );

    registration.addUrlMappings("/", "/testCustomer/*"  );

    for ( Office office : officeService.findAllActiveOffices() ) {
        registration.addUrlMappings( office.getUrl() + "/*" );
    }
    return registration;
}

但这似乎只有在应用程序在启动时就知道客户的情况下才有效,而不是在客户注册的情况下动态地工作。

有没有办法配置它来处理这些类型的通配符?

【问题讨论】:

  • 这是一个带有@PathVariable 绑定的私有方法(可能不适用于Spring MVC)?
  • @Dave - 哎呀,谢谢你的收获。不幸的是,这对我的问题并没有真正的影响。 ServletRegistrationBean 方法似乎是一个开始,无论如何在运行时动态更新 ServletRegistrationBean(即 - 新客户注册)?
  • 如果你必须这样做,我真的不明白用例。 Spring MVC 可以动态匹配路径(就像您尝试使用 @PathVariable 一样),因此您真的应该使用该功能。
  • 戴夫是对的。顺便说一下。密码编码器应该是一个 bean。并且antMatchers是一个可变参数方法,所以,可以只写2的前10行。如果"/css/**""/fonts/**""/libs/**"已经被忽略,则需要在antMatchers中添加它们以获得permitAll。和戴夫一样,我不了解用例。这已经是@PathVariable 的标称行为了。你为什么需要那个?
  • 我还以为 Spring-MVC 会处理动态 URL,但是没有 ServletRegistrationBean,URL 将不会呈现。我假设这是 spring-security 阻止它。

标签: spring-security spring-boot


【解决方案1】:

您可以尝试如下配置:

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private UserDetailsService _userService;

  @Autowired
  private PasswordEncoder _passwordEncoder;

  /**
   * Defines the password encoder used by Spring security during the
   * authentication procedure.
   */
  @Bean
  public PasswordEncoder passwordEncoder() {
    // default strength = 10
    return new BCryptPasswordEncoder();
  }

  /**
   * Sets security configurations for the authentication manager
   */
  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth)
      throws Exception {
    auth
      .userDetailsService(_userService)
      .passwordEncoder(_passwordEncoder);
    return;
  }

  /**
   * Configures where Spring Security will be disabled (security = none).
   * From spring reference: "Typically the requests that are registered [here]
   * should be that of only static resources. For requests that are dynamic,
   * consider mapping the request to allow all users instead."
   */
  @Override
  public void configure(WebSecurity web) throws Exception {
      web.ignoring()
        .antMatchers(
          "/css/**",
          "/js/**",
          "/fonts/**",
          "/resources/**",
          "/libs/**");
      return;
  }

  /**
   * Sets security configurations in the HttpSecurity object.
   */
  @Override
  protected void configure(HttpSecurity http) throws Exception {

    // Set security configurations
    http
      .authorizeRequests()
        // the following urls are allowed for any user (no authentication)
        .antMatchers(
            "/",
            "/login",
            "/menu")
            .permitAll()
        // any other url must be authenticated
        .anyRequest().authenticated()
        .and()
      // define the login page url
      .formLogin()
        .loginPage("/login")
        .permitAll()
        .and()
      // define the logout url
      .logout()
        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
        .logoutSuccessUrl("/login?logout")
        .permitAll();

    return;
  } // method configure

} // class WebSecurityConfig

正在添加您的个人配置...您可以尝试添加以下控制器:

@Controller
public class HomeController {

  @RequestMapping("/{officeName}/")
  public AuthenticatedUser getVisitor(@PathVariable String officeName) {

    // .. do something with the office if found, redirect otherwise
    if (!StringUtils.isEmpty(officeName)) {
        Office office = officeService.findByName( officeName );
        return office.getUrl();
    }

    return "/";
  }
}

如果用户通过了正确的身份验证,他应该访问 officeName 处的 url。

【讨论】:

  • 谢谢安德里亚,这肯定会清理我的配置。但是,这仍然需要通过登录页面对用户进行身份验证。我确实看到 HomeController 在登录尝试后被调用,但我希望我可以配置它,以便所有用户都可以访问 url,例如: .antMatchers("/", "/login", "/向导”、“/menu”、“/error”、“/{officeName}/”).permitAll();
  • 尝试使用像 .antMatchers("/", "/*/").permitAll().anyRequest().authenticated(); 这样的 antMatchers 来允许像“/{officeName}/”这样的任何 url。在您的控制器中,您可以检查是否尝试了无效的 officeName,然后重定向用户。任何像“mysite.com/customerA/myaccount/”这样的网址都必须经过身份验证。
  • 谢谢,这正是我需要的。我将用完成的代码更新我的问题。根据 Dave 的评论,这是一个罕见的用例,但也许有一天有人会发现它很有用。
猜你喜欢
  • 2010-11-13
  • 2020-09-16
  • 2023-01-03
  • 2018-09-08
  • 1970-01-01
  • 2020-05-19
  • 1970-01-01
  • 2017-08-26
相关资源
最近更新 更多