Spring安全自定义令牌过滤器

时间:2014-03-12 19:02:39

标签: java spring spring-security spring-java-config

我正在尝试执行自定义过滤器以获取令牌并对其进行验证。我正在遵循response中的方法。

这是相关配置:

SecurityConfig:

@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = {"com.company.app"})
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Inject
AuthenticationTokenFilter authenticationTokenFilter;

@Inject
TokenAuthenticationProvider tokenAuthenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .addFilterBefore(authenticationTokenFilter, BasicAuthenticationFilter.class)
                .antMatcher("/*")
                .authenticationProvider(tokenAuthenticationProvider)
                .authorizeRequests()
                    .anyRequest().authenticated();
    }

}

AuthenticationTokenFilter:

@Component
public class AuthenticationTokenFilter implements Filter {

private static final Logger logger = LoggerFactory.getLogger(AuthenticationTokenFilter.class);

@Override
public void init(FilterConfig fc) throws ServletException {
    logger.info("Init AuthenticationTokenFilter");
}

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
    SecurityContext context = SecurityContextHolder.getContext();
    if (context.getAuthentication() != null && context.getAuthentication().isAuthenticated()) {
        // do nothing
    } else {
        Map<String,String[]> params = req.getParameterMap();
        if (!params.isEmpty() && params.containsKey("auth_token")) {
            String token = params.get("auth_token")[0];
            if (token != null) {
                Authentication auth = new TokenAuthentication(token);
                SecurityContextHolder.getContext().setAuthentication(auth);
            }
        }
    }

    fc.doFilter(req, res);
}

@Override
public void destroy() {

}
}

TokenAuthentication:

public class TokenAuthentication implements Authentication {
private String token;

public TokenAuthentication(String token) {
    this.token = token;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    return new ArrayList<GrantedAuthority>(0);
}
@Override
public Object getCredentials() {
    return token;
}
@Override
public Object getDetails() {
    return null;
}
@Override
public Object getPrincipal() {
    return null;
}
@Override
public boolean isAuthenticated() {
    return false;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
}
@Override
public String getName() {
    return null;
}
}

TokenAuthenticationProvider:

@Component
public class TokenAuthenticationProvider implements AuthenticationProvider {

private static final Logger logger = LoggerFactory.getLogger(TokenAuthenticationProvider.class);

@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {
    if (auth.isAuthenticated())
        return auth;

    String token = auth.getCredentials().toString();
    User user = userSvc.validateApiAuthenticationToken(token);
    if (user != null) {
        auth = new PreAuthenticatedAuthenticationToken(user, token);
        auth.setAuthenticated(true);
        logger.debug("Token authentication. Token: ");
    } else
        throw new BadCredentialsException("Invalid token " + token);
    return auth;
}

@Override
public boolean supports(Class<?> aClass) {
    return true;
}

}

但它就像没有将AuthenticationTokenFilter添加到链中。调试我可以看到,当我进行调用时,它会进入SecurityConfig并配置方法,但不会进入过滤器。 缺少什么?

4 个答案:

答案 0 :(得分:4)

尝试禁用anonymous身份验证,并将fully身份验证更改为您的安全规则。

类似的东西:

http
    .addFilterBefore(authenticationTokenFilter, BasicAuthenticationFilter.class)
                    .antMatcher("/token")
                    .authenticationProvider(tokenAuthenticationProvider)
                    .authorizeUrls().anyRequest().fullyAuthenticated()
    .and()
                    .anonymous().disable()  

答案 1 :(得分:2)

你缺少的是

<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>
您的web.xml中的

或类路径中的初始化程序的等效项:

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

@Order(value = 1)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}

这与WebApplicationInitializer分开。请注意:

  • 您的SecurityConfig(或任何使用@EnableWebSecurity注释的内容)必须在根上下文中定义(而非调度程序上下文)
  • 你可能应该理解order of initialization(我不确定我是否这样做):
  

&#34; WebApplicationInitializer的排序&#34;
  如果在调用AbstractSecurityWebApplicationInitializer之后添加了任何servlet Filter映射,则可能会在springSecurityFilterChain之前意外添加它们。除非应用程序包含不需要保护的Filter实例,否则springSecurityFilterChain应该在任何其他Filter映射之前。 @Order注释可用于帮助确保以确定的顺序加载任何WebApplicationInitializer。

示例:

@Order(value = 10)
public class AppWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

  @Override
  protected Class<?>[] getRootConfigClasses() {
      return new Class<?>[] { AppConfig.class, SecurityConfig.class };
  }

  @Override
  protected Class<?>[] getServletConfigClasses() {
      return new Class<?>[] { RestConfig.class };
  }

  @Override
  protected String[] getServletMappings() {
      return new String[] { "/rest/*"};
  }
}


总结一下,来自Spring文档:

  

使用servlet过滤器时,显然需要在web.xml中声明它们,否则servlet容器将忽略它们。在Spring Security中,过滤器类也是在应用程序上下文中定义的Spring bean,因此能够利用Spring丰富的依赖注入工具和生命周期接口。 Spring的DelegatingFilterProxy提供了web.xml和应用程序上下文之间的链接。

The Security Filter Chain

答案 2 :(得分:0)

旧帖子,但我认为authenticationProvider()需要在“addBeforeFilter”之前出现。不确定它今天是否会有所作为,但它可能很重要。这可能无关紧要。

另外,请尝试在配置类上添加此项以解决此问题:

@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

答案 3 :(得分:0)

仅供参考:同时使用过滤器上的@Component@InjectaddFilterBefore一起将两次应用过滤器!在您的情况下,这只是更多的处理时间,因此您不会看到任何错误。但是,如果您要注入指标过滤器,那么您将获得错误的指标。