从AuthenticationProvider成功进行身份验证后,Spring安全性出现错误。从堆栈跟踪中看起来像多次调用Spring Security Filter。
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
我已经在这里发布了关于我的问题的问题-Spring Security - Unable to Autowire UserDetailsService in DaoAuthenticationProvider在这里,我试图使用DaoAuthenticationProvider,但是没有运气。
因此,尝试立即使用身份验证提供程序并获得错误。 SpringSecurity Filter被多次调用的原因可能是什么。请帮忙!
这是我当前的代码-
RESTSecurityConfig
@Configuration
@EnableWebSecurity
@Order(1)
public class RESTSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public RESTSecurityFilter authenticationFilter() throws Exception {
RESTSecurityFilter authenticationFilter = new RESTSecurityFilter("/");
authenticationFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationFilter;
}
@Bean
public RESTAuthenticationProvider authenticationProvider() {
RESTAuthenticationProvider provider = new RESTAuthenticationProvider();
return provider;
}
@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
RESTSecurityFilter
public class RESTSecurityFilter extends AbstractAuthenticationProcessingFilter {
private static final Logger log = LoggerFactory.getLogger(RESTSecurityFilter.class);
private static final String ACCESS_KEY_PARAMETER_NAME = "x-access-key";
private static final String SIGNATURE_PARAMETER_NAME = "x-signature";
private static final String NONCE_PARAMETER_NAME = "x-nonce";
private static final String TIMESTAMP_PARAMETER_NAME = "x-timestamp";
private static final String SECRET_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
protected RESTSecurityFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
String accessKey = getHeaderValue(request, ACCESS_KEY_PARAMETER_NAME);
String signature = getHeaderValue(request, SIGNATURE_PARAMETER_NAME);
String nonce = getHeaderValue(request, NONCE_PARAMETER_NAME);
String timestamp = getHeaderValue(request, TIMESTAMP_PARAMETER_NAME);
String message = accessKey + ":" + nonce + ":" + timestamp;
String hashSignature = null;
try {
hashSignature = HMacUtility.calculateHmac(message, SECRET_KEY);
log.info("hashSignature : {}", hashSignature);
}
catch (InvalidKeyException | SignatureException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
AbstractAuthenticationToken authRequest = createAuthenticationToken(accessKey,
new RESTCredentials(hashSignature, signature));
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, authResult);
chain.doFilter(request, response);
// return; // <--- If uncommented, error goes away but response gets stuck in infinite loop
}
private String getHeaderValue(HttpServletRequest request, String headerParameterName) {
return (request.getHeader(headerParameterName) != null) ? request.getHeader(headerParameterName) : "";
}
private AbstractAuthenticationToken createAuthenticationToken(String apiKeyValue, RESTCredentials restCredentials) {
return new RESTAuthenticationToken(apiKeyValue, restCredentials);
}
protected void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
@Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
return true;
}
}
RestAuthenticationProvider
public class RESTAuthenticationProvider implements AuthenticationProvider {
private static final Logger log = LoggerFactory.getLogger(RESTAuthenticationProvider.class);
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException{
String userName = authentication.getName();
RESTCredentials credentials = (RESTCredentials) authentication.getCredentials();
String cred1 = credentials.getRequestSalt();
String cred2 = credentials.getSecureHash();
Authentication auth = null;
List<String> rolesList = new ArrayList<>();
rolesList.add("ROLE_USER");
rolesList.add("ROLE_ADMIN");
if (userName.equals("abc") && cred1.equalsIgnoreCase(cred2)) {
Collection<GrantedAuthority> grantedAuths = new ArrayList<>();
for (String role : rolesList) {
grantedAuths.add(new SimpleGrantedAuthority(role.trim()));
}
auth = new UsernamePasswordAuthenticationToken(userName, cred1, grantedAuths);
return auth;
}
else {
throw new BadCredentialsException("Invalid credentials!");
}
}
@Override
public boolean supports(Class<? extends Object> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}
错误的堆栈跟踪-
10:34:46.336 [http-nio-8888-exec-1] DEBUG c.s.m.security.RESTSecurityFilter - Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@fb74cbae: Principal: srib; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER, ROLE_ADMIN
10:34:46.338 [http-nio-8888-exec-1] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: Cannot call sendError() after the response has been committed] with root cause
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:472)
at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129)
at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129)
at org.springframework.security.web.util.OnCommittedResponseWrapper.sendError(OnCommittedResponseWrapper.java:115)
at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129)
at org.springframework.security.web.util.OnCommittedResponseWrapper.sendError(OnCommittedResponseWrapper.java:115)
at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:488)
at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:53)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at xxxxxxxxxxxxxxxxxxxxx.security.RESTSecurityFilter.successfulAuthentication(RESTSecurityFilter.java:86)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:240)