【问题标题】:Add filter to Spring security to implement multi tenant为 Spring Security 添加过滤器以实现多租户
【发布时间】:2018-01-31 08:06:33
【问题描述】:

我需要更新我的 Spring Security 配置以引入多租户管理(我在其中获取每个 Web 请求的 URL,并通过配置文件检索正确的架构)。 所以我添加了一个过滤器(因为处理程序登录页面没有正确的模式,因为处理程序是在 spring 安全性之后调用的)到我的 spring 安全性配置但现在我捕获了 URL,设置了模式但页面仍然是空的并且没有'不重定向到登录页面,如果我写 /login 也不会出现 HTML 页面。

这就是我配置 Spring Security 的方式:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;
    @Autowired
    private RoleServices roleServices;
    @Autowired
    private CustomSuccessHandler customSuccessHandler;

    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth)throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource)
        .passwordEncoder(passwordEncoder())
        .usersByUsernameQuery("select username,password,enabled from user where username=?")
        .authoritiesByUsernameQuery("select u.username, CONCAT('ROLE_' , r.role) from user u inner join role r on u.idRole = r.idRole where lower(u.username) = lower(?)");
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
        //Spring Security ignores request to static resources such as CSS or JS files.
        .ignoring()
        .antMatchers("/static/**","/users/{\\d+}/password/recover","/users/{\\d+}/token/{\\d+}/password/temporary")
        .antMatchers(HttpMethod.PUT,"/users/{\\d+}/token/{\\d+}/password/temporary");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        List<Role> roles=roleServices.getRoles();
        //Retrieve array of roles(only string field without id)
        String[] rolesArray = new String[roles.size()];
        int i=0;
        for (Role role:roles){
            rolesArray[i++] = role.getRole();
        }

        http
           .authorizeRequests() //Authorize Request Configuration
           .anyRequest().hasAnyRole(rolesArray)//.authenticated()
        .and()//Login Form configuration for all others
           .formLogin()
           .loginPage("/login").successHandler(customSuccessHandler)
        //important because otherwise it goes in a loop because login page require authentication and authentication require login page
           .permitAll()
        .and()
           .exceptionHandling().accessDeniedPage("/403")
        .and()
           .logout()
           .logoutSuccessUrl("/login?logout")
           .deleteCookies("JSESSIONID", "JSESSIONID")
           .invalidateHttpSession(true)
           .permitAll()
        .and()
           .sessionManagement().invalidSessionUrl("/login")
        .and()
           .addFilterAfter(new MultiTenancyInterceptor(), BasicAuthenticationFilter.class);

            }
        }

我在设置租户的地方添加了MultiTenancyInterceptor 过滤器

@Component
public class MultiTenancyInterceptor extends OncePerRequestFilter   {

    @Override
    public void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain)
            throws IOException, ServletException {  
        String url = request.getRequestURL().toString();
        URI uri;
        try {
            uri = new URI(url);
            String domain = uri.getHost();
            if(domain!=null){
                TenantContext.setCurrentTenant(domain);
            }   
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }   
}

但是当我写登录页面的控制器时没有收到调用:

@Override
@RequestMapping(value = { "/login" }, method = RequestMethod.GET)
public String loginPage(){
    return "login";
}

您在我的configure 方法中看到错误了吗?如果您需要更多信息,我可以添加其他类。谢谢 PS:我注意到doFilter 会为每个页面请求调用两次

【问题讨论】:

    标签: java spring spring-mvc spring-security multi-tenant


    【解决方案1】:

    最好的方法是实现过滤器接口并做一些你的 url 逻辑,然后使用 filterChain.doFilter(request, response); 将其转发到下一个操作 确保在 web.xml 中添加此过滤器。

    无论哪种方式,您都可以使用 spring org.springframework.web.servlet.handler.HandlerInterceptorAdapter 来处理 http 请求的前后处理。 Spring 在内部转发到下一个控制器请求方法。

    例如:https://www.mkyong.com/spring-mvc/spring-mvc-handler-interceptors-example/

    【讨论】:

    • HandlerInterceptorAdapter 不适用于 Spring Security
    • 嗨@luca 我已经使用过滤器来获取tenantId但得到401异常。你能帮帮我吗。
    • 问题太笼统了,可能是身份验证凭据问题
    【解决方案2】:

    根据dur的建议,我添加了代码

    filterChain.doFilter(request, response);
    

    在过滤方法结束时

    【讨论】:

      猜你喜欢
      • 2012-04-01
      • 1970-01-01
      • 2019-04-13
      • 2023-03-25
      • 1970-01-01
      • 2014-09-04
      • 2014-09-29
      • 2020-11-21
      • 2017-11-19
      相关资源
      最近更新 更多