为什么Spring Security不允许对匿名用户进行身份验证?

时间:2016-04-22 09:35:06

标签: spring spring-mvc authentication spring-security spring-aspects

这是我在Spring日志中的消息:

[DEBUG] 2016-04-22 10:39:19,469 [] [-254028363]  org.springframework.security.web.access.intercept.FilterSecurityInterceptor authenticateIfRequired - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@6faa3d44: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff4c9c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: F5BF9CC6CFE7D2C98A0CB043F4D5C10F; Granted Authorities: ROLE_ANONYMOUS

org.springframework.security.web.access.intercept.FilterSecurityInterceptor 
authenticateIfRequired - Previously Authenticated
org.springframework.security.authentication.AnonymousAuthenticationToken@6faa3d44: 
Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; 
Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff4c9c:
RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: F5BF9CC6CFE7D2C98A0CB043F4D5C10F;
Granted Authorities: ROLE_ANONYMOUS

考虑到org.springframework.security.access.intercept.AbstractSecurityInterceptor.class的" authenticateIfRequired()" 方法的实现:

/**
 * Checks the current authentication token and passes it to the AuthenticationManager
 * if {@link org.springframework.security.core.Authentication#isAuthenticated()}
 * returns false or the property <tt>alwaysReauthenticate</tt> has been set to true.
 *
 * @return an authenticated <tt>Authentication</tt> object.
 */
private Authentication authenticateIfRequired() {
    Authentication authentication = SecurityContextHolder.getContext()
            .getAuthentication();

    if (authentication.isAuthenticated() && !alwaysReauthenticate) {
        if (logger.isDebugEnabled()) {
            logger.debug("Previously Authenticated: " + authentication);
        }

        return authentication;
    }

    authentication = authenticationManager.authenticate(authentication);

    // We don't authenticated.setAuthentication(true), because each provider should do
    // that
    if (logger.isDebugEnabled()) {
        logger.debug("Successfully Authenticated: " + authentication);
    }

    SecurityContextHolder.getContext().setAuthentication(authentication);

    return authentication;
}

这种情况的结果是&#39; anonymousUser&#39;从未经过身份验证

我从来没有在Spring日志中看到&#34;成功通过身份验证:&#34; 以及<#39; anonymousUser&#39;

此外, SecurityContextHolder 不包含任何身份验证对象,因为从不执行此行代码:

SecurityContextHolder.getContext().setAuthentication(authentication);

实际上,如果我执行SecurityContextHolder.getContext()。getAuthentication(),我有一个null对象作为返回。

此行为与文档中的内容不匹配:

http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#anonymous-overview

  

这就是匿名身份验证的含义。请注意有   匿名的用户之间没有真正的概念差异   认证&#34;和一个未经身份验证的用户。 Spring Security的   匿名身份验证只是为您提供了一种更方便的方法   配置访问控制属性。调用servlet API调用   例如,getCallerPrincipal仍然会返回null   虽然实际上有一个匿名身份验证对象     SecurityContextHolder中。

     

还有其他匿名情况   身份验证很有用,例如审计拦截器查询时   SecurityContextHolder用于标识哪个主体     负责给定的操作。可以更多地编写类   如果他们知道 SecurityContextHolder总是包含一个   身份验证对象,永不为空

为什么会这样? 就我而言,身份验证对象永远不会为空。

这是我的Java配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
public class SecurityContextConfig extends WebSecurityConfigurerAdapter{

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/index.html","/myApp/pages/**").permitAll().and()
            .authorizeRequests().anyRequest().authenticated().and()
            .httpBasic().and()
            .csrf().csrfTokenRepository(csrfTokenRepository()).and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
            .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).permitAll().logoutSuccessUrl("/index.html");
    }

    // ...
}

有什么想法吗? 谢谢!

修改

这是方法调用的完整堆栈&#34; authenticateIfRequired()&#34;:

    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.authenticateIfRequired(AbstractSecurityInterceptor.java:345)
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:228)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:123)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at myApp.security.config.SecurityContextConfig$1.doFilterInternal(SecurityContextConfig.java:150)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at myApp.filter.RequestFilter.doFilter(RequestFilter.java:21)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:521)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1096)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:674)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

这是我目前的实施:

public class MyDaoAuthenticationProvider extends DaoAuthenticationProvider {

    @Autowired
    AuthenticationHandler authenticationHandler;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        Authentication authenticated = null;

        try {
            authenticated = super.authenticate(authentication);
        } catch (Exception e) {
            e.printStackTrace();
            authenticationHandler.handleFailedAuthentication(authentication.getName());
            throw e;
        }

        // this works
        SecurityContextHolder.getContext().setAuthentication(authentication);
        authenticationHandler.handleSuccessAuthentication(authentication.getName());
        return authenticated;
    }

}

当我需要当前用户的通知时,在@MappedSuperclass中调用SecurityContextHolder.getContext()。getAuthentication()。

public abstract class TableObject implements Serializable {

    @PreUpdate
    protected void onUpdate() {
        userModifier = SecurityContextHolder.getContext().getAuthentication().getName();
// this don't work
    }

}

0 个答案:

没有答案