我意识到我对这个游戏有点晚了,但我也设法让API密钥与Spring Boot一起工作,并与用户名/密码身份验证一起工作。我对使用这个想法并不疯狂,因为在阅读JavaDoc时,它似乎是对该特定类的滥用。AbstractPreAuthenticatedProcessingFilter
我最终创建了一个新类以及一个非常简单的原始servlet过滤器来完成此操作:ApiKeyAuthenticationToken
import java.util.Collection;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.Transient;
@Transient
public class ApiKeyAuthenticationToken extends AbstractAuthenticationToken {
private String apiKey;
public ApiKeyAuthenticationToken(String apiKey, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.apiKey = apiKey;
setAuthenticated(true);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return apiKey;
}
}
和过滤器
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
public class ApiKeyAuthenticationFilter implements Filter {
static final private String AUTH_METHOD = "api-key";
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
if(request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
String apiKey = getApiKey((HttpServletRequest) request);
if(apiKey != null) {
if(apiKey.equals("my-valid-api-key")) {
ApiKeyAuthenticationToken apiToken = new ApiKeyAuthenticationToken(apiKey, AuthorityUtils.NO_AUTHORITIES);
SecurityContextHolder.getContext().setAuthentication(apiToken);
} else {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(401);
httpResponse.getWriter().write("Invalid API Key");
return;
}
}
}
chain.doFilter(request, response);
}
private String getApiKey(HttpServletRequest httpRequest) {
String apiKey = null;
String authHeader = httpRequest.getHeader("Authorization");
if(authHeader != null) {
authHeader = authHeader.trim();
if(authHeader.toLowerCase().startsWith(AUTH_METHOD + " ")) {
apiKey = authHeader.substring(AUTH_METHOD.length()).trim();
}
}
return apiKey;
}
}
此时剩下的就是将过滤器注入链中的正确位置。在我的情况下,我希望在任何用户名/密码身份验证之前评估API密钥身份验证,以便在应用程序尝试重定向到登录页面之前对请求进行身份验证:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.addFilterBefore(new ApiKeyAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and()
.formLogin();
}
我要说的另一件事是,您应该注意的是,您的API密钥身份验证请求不会在服务器上创建和放弃一堆。HttpSession