簡體   English   中英

Spring 安全自定義令牌過濾器

[英]Spring security custom token filter

我正在嘗試執行自定義過濾器以獲取令牌並對其進行驗證。 我正在遵循此響應中的方法。

這是相關的配置:

安全配置:

@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();
    }

}

身份驗證令牌過濾器:

@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() {

}
}

令牌認證:

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 和 configure 方法,但不會進入過濾器。 有什么不見了?

嘗試禁用anonymous身份驗證並更改為對您的安全規則進行fully身份驗證。

像這樣:

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

你缺少的是

<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 注釋的東西)必須在根上下文(而不是調度程序上下文)中定義
  • 您可能應該了解初始化的順序(我不確定我是否了解):

“WebApplicationInitializer 的排序”
如果在調用 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 和應用程序上下文之間的鏈接。

安全過濾器鏈

舊帖子,但我認為 authenticationProvider() 需要在“addBeforeFilter”之前出現。 不確定它今天是否會有所作為,但它可能很重要。 可能沒有那么重要。

還可以嘗試在您的配置類中添加它以解決問題:

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

僅供參考:在過濾器上使用@Component和在addFilterBefore使用@Inject將應用過濾器兩次! 在你的情況下,它只是更多的處理時間,所以你不會看到任何錯誤。 但是,如果您正在注入指標過濾器,那么您將獲得錯誤的指標。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM