Spring-Security基于标头管理两个AuthenticationFilters

时间:2019-03-11 17:16:34

标签: java spring-boot authentication spring-security

在我的spring-boot应用程序(这是一个基本的Rest API)中,我必须管理两种身份验证:

  • 一个基于令牌的令牌,当令牌出现在http标头X-API-TOKEN中时,我必须验证并提取userId
  • 当我获得标头“ Authorization = Basic xxx”和标头X-API-USER-ID的组合时,另一个基于BasicAuth的方法

我实现了分别实现每个用例的功能,但是我无法使用这两个过滤器进行这样的配置。 我在控制器上使用Pre / PostAuthorize注释,因为某些方法受到限制,而其他方法则允许所有人使用,而无需任何令牌或basicAuth + uid

这是我的安全配置:

    func applicationWillTerminate(_ application: UIApplication) {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.

    locationManager = nil

}

TokenFilter:

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

    @Autowired
    private UserService userConnector;

    @Autowired
    private TokenEncoder tokenEncoder;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests().antMatchers("/").permitAll().and()
                .authorizeRequests().antMatchers("/console/**").permitAll();

        httpSecurity.csrf().disable();
        httpSecurity.headers().frameOptions().disable();

        httpSecurity.addFilterAfter(basicAuthFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterAfter(tokenFilter(), BasicAuthenticationFilter.class)
                .exceptionHandling()
                .authenticationEntryPoint(myExceptionHandler())
                .accessDeniedHandler(myExceptionHandler());
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

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

    @Bean
    public BasicAuthorizationFilter basicAuthFilter() {
        return new BasicAuthorizationFilter();
    }

    @Bean
    public MyTokenAuthorizationFilter tokenFilter() {
        return new MyTokenAuthorizationFilter(tokenEncoder);
    }

    @Bean
    public MyExceptionHandler myExceptionHandler() {
        return new MyExceptionHandler();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsService() {
        return userConnector;
    }
}

另一个过滤器:

public class MyTokenAuthorizationFilter extends OncePerRequestFilter {

    private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    private TokenEncoder tokenEncoder;

    private RememberMeServices rememberMeServices = new NullRememberMeServices();


    public MyTokenAuthorizationFilter(TokenEncoder tokenEncoder) {
        super();
        this.tokenEncoder = tokenEncoder;
    }

    @Override
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        if(request.getHeader("X-API-TOKEN") == null) {
            filterChain.doFilter(request, response);
        } else {
            String uid = tokenEncoder.isValid(request.getHeader("X-API-TOKEN"));
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(uid, "");
            token.setDetails(authenticationDetailsSource.buildDetails(request));
            Authentication authResult = authenticationManager.authenticate(token);
            SecurityContextHolder.getContext().setAuthentication(token);
            rememberMeServices.loginSuccess(request, response, authResult);
        }
        filterChain.doFilter(request, response);
    }


    @Override
    public void afterPropertiesSet() {
        Assert.notNull(authenticationManager,
                "An AuthenticationManager is required");
        Assert.notNull(this.authenticationEntryPoint,
                "An AuthenticationEntryPoint is required");
    }
}

我很满意这两个过滤器都在工作,但问题是它们没有被链接。似乎该请求在两个过滤器上传播了两次,并且根据spring-security文档,我的json回答加倍了,这是正常的。 如何根据我在标头中找到的内容执行每个过滤器,如果其中一个成功,请跳过第二个步骤?

0 个答案:

没有答案