在生产中,模拟验证spring安全-来自反向代理;但我的过滤器没有被注入

r8uurelv  于 2021-07-14  发布在  Java
关注(0)|答案(1)|浏览(332)

热释光;博士

我需要一个javaservet过滤器来接收注入的依赖项,就像我的其他类一样(其他的都是从spring自己的servlet调用的)
为什么? @Inject 没有效果-停留 null ? (我正在添加新的过滤器 web.xml 但传统的方法是行不通的。但可能需要与spring filter delegator或 <bean> ?
如何将筛选器加载为 <bean> 所以 @Inject 行吗?

完整问题

概述

我对Spring知之甚少。这是我们的资料
spring身份验证
似乎是 Spring 会议管理
我们想要的是
反向代理服务器处理身份验证(我将创建)
基于http头模拟成功的身份验证(筛选器读取反向代理传递的头,验证它们,然后不需要身份验证,因为反向代理已经在该端执行了此操作)
使用类似 SecurityContextUtil.setAuthentication(auth) 将允许所有现有的身份验证使用读取我的模拟对象。这样,并不是每个页面或端点都需要读取反向代理标头,因为筛选器会这样做

我们所拥有的

web.xml 我们有

<filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

我们有 MySecurityConfig.java ,它作为类名从未被引用,所以我假设spring必须扫描所有类中的一个注解并找到这个注解。

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

       @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
       @Override
       public AuthenticationManager authenticationManagerBean() throws Exception {
           return super.authenticationManagerBean();
       }

    @Override
    protected void configure(
      AuthenticationManagerBuilder auth) throws Exception {

        auth
            .authenticationProvider(authProvider())
            .authenticationEventPublisher(eventPublisher());
    }

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

        ...

        http
                .csrf()
                    .ignoringAntMatchers("...")
                    .csrfTokenRepository(cookieCsrfRepo)
            .and()
                .authorizeRequests()
                    .antMatchers("/...").permitAll()
                    .antMatchers("/...").hasRole("...")
                    .antMatchers("/...").hasRole("...")
            .and()
                .formLogin()
                .loginPage("/...")
                ...
                .loginProcessingUrl("/...")
                .authenticationDetailsSource(myAuthenticationDetailsSource)
                .successHandler(myAuthenticationSuccessHandler())
                .failureHandler(myAuthenticationFailureHandler)
                .permitAll()       
            .and()  
                .logout()
                .logoutSuccessHandler(myLogoutSuccessHandler)
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
    }

    @Bean
    public MyAuthenticationSuccessHandler myAuthenticationSuccessHandler() {
        return new MyAuthenticationSuccessHandler();
    }

    @Bean
    public AuthenticationProvider authProvider() {
        return new MyAuthenticationProvider();
    }

    @Bean
    public AuthenticationEventPublisher eventPublisher() {
        return new DefaultAuthenticationEventPublisher();
    }
}

我注意到了

每当产生新线程时,身份验证都会附加到新线程,如下所示:

SecurityContextUtil.setAuthentication(auth);

在某个测试中,我们模拟身份验证如下:

@Inject
    private AuthenticationManager am;

    @Before
    public void authenticateTestUser() {
        MyAuthenticationDetails details = mock(MyAuthenticationDetails.class); // Mockito
        when(details.getThing()).thenReturn(...);
        when(details.getThing()).thenReturn(...);

        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken("username", "password");
        usernamePasswordAuthenticationToken.setDetails(details);

        Authentication request = usernamePasswordAuthenticationToken;
        Authentication result = am.authenticate(request);
        SecurityContextHolder.getContext().setAuthentication(result);
    }

我试过的

注意到上面的内容,我打算简单地创建一个过滤器。
web.xml 我尝试了一个传统的JavaServlet过滤器。

<filter>
        <filter-name>reverseProxyAuthReceivingFilter</filter-name>
        <filter-class>com.example.my.ReverseProxyAuthReceivingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>reverseProxyAuthReceivingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
public class ReverseProxyAuthReceivingFilter implements Filter {

    @Inject
    private AuthenticationManager am; // org.springframework.security.authentication.AuthenticationManager

    @Inject
    private LoginUserService userService; // JPA

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
       ...

不幸的是 am 为空,因此我不能使用相同的 AuthenticationManager . 所以我打算自己从数据库中创建对象,但是我也无法加载jpa依赖项。。。

让我们集中注意力。

我在想如果我能学会 LoginUserService (有一个 @Service 它的注解)注入一个新的过滤器,将是最好的。
我到处找,尝试了一些 <bean> 但到目前为止我还没有成功。
如何将筛选器加载为 <bean> 所以 @Inject 行吗?

5f0d552i

5f0d552i1#

多亏了m。deinum的评论提到了安全过滤器链过滤器,我发现了解决方案。
MySecurityConfig.java (有 @EnableWebSecurity 在上面)

@Inject
    ReverseProxyAuthReceivingFilter reverseProxyAuthReceivingFilter;

    ...
    http.addFilterBefore(reverseProxyAuthReceivingFilter, BasicAuthenticationFilter.class)

(根据(自定义)重新验证ProcessingFilter排序的例外情况,我们必须使用 addFilterBefore 或者 addFilterAfter )
applicationContext.xml ```

public class ReverseProxyAuthReceivingFilter implements Filter {

// Dependency injection works when filter is Bean! Yay!
@Inject
private AuthenticationManager am;

@Inject
private LoginUserService userService;

@Override
public void doFilter(ServletRequest reqO, ServletResponse resO, FilterChain chain) throws ServletException, IOException {
    HttpServletRequest req = (HttpServletRequest) reqO;
    if (...) {
        MyAuthenticationDetails details = new MyAuthenticationDetails(...);

        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken("username", "password");
        usernamePasswordAuthenticationToken.setDetails(details);

        Authentication request = usernamePasswordAuthenticationToken;
        Authentication result = am.authenticate(request);

...

相关问题