簡體   English   中英

Spring Security 自定義過濾器被多次調用

[英]Spring Security Custom Filter gets called Multiple times

我有一個自定義 Spring Security 過濾器,它被多次調用,但我不知道為什么。 我搜索了它並嘗試按照某些帖子的建議添加FilterRegistrationBean但我的 Secuirty 過濾器仍然被多次調用並拋出以下錯誤 -

20:57:49.975 [http-nio-8888-exec-2] DEBUG c.s.m.security.RESTSecurityFilter - Authentication success. Updating SecurityContextHolder to contain: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@fb70fff6: Principal: srib; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@43458: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: BC1D5AB21EE4586F2A76C7901F1F953F; Granted Authorities: ROLE_USER, ROLE_ADMIN
20:57:50.220 [http-nio-8888-exec-2] 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 xxxxxxxxxxxxxxxxxxxxxx.RESTSecurityFilter.successfulAuthentication(RESTSecurityFilter.java:83)

以下是我的配置和過濾器 -

REST安全配置

@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() {            
        return new RESTAuthenticationProvider();
    }

    @Bean
    public FilterRegistrationBean registration() {
        RESTSecurityFilter authenticationFilter = new RESTSecurityFilter("/");
        FilterRegistrationBean registration = new FilterRegistrationBean(authenticationFilter);
        registration.setEnabled(false);
        return registration;
    }

    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
   http.authorizeRequests().anyRequest().authenticated().and().addFilterAfter(authenticationFilter(),
                UsernamePasswordAuthenticationFilter.class);
    }
}

REST安全過濾器

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;
    }
}

這是因為Spring Boot 選擇了任何公開為@Bean Filter並將其添加到ServletContext 通過將其公開為@Bean並將其添加到 Spring Security Filter Chain,您實際上已將其注冊了兩次。

很可能,您可以簡單地從authenticationFilter()方法中刪除@Bean注釋。

暫無
暫無

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

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