[英]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 是分开的。 注意:
“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.