1

这是我在 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;
}

这种情况的结果是'anonymousUser' 从未经过身份验证

我从未在 Spring 日志中看到“anonymousUser”的跟踪“Successfully Authenticated:” 。

此外,SecurityContextHolder不会包含任何 Authentication对象,因为这行代码从未执行过:

SecurityContextHolder.getContext().setAuthentication(authentication);

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

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

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

这就是我们所说的匿名身份验证。请注意,“匿名身份验证”的用户和未经身份验证的用户之间在概念上没有真正的区别。Spring Security 的匿名身份验证只是为您提供了一种更方便的方式来配置访问控制属性。例如,对 servlet API 调用(例如 getCallerPrincipal)的调用仍将返回 null,即使 SecurityContextHolder 中实际上存在匿名身份验证对象。

在其他情况下匿名身份验证很有用,例如当审计拦截器查询 SecurityContextHolder 以确定哪个主体负责给定操作时。如果类知道SecurityContextHolder 始终包含一个 Authentication 对象,并且从不为 null ,则可以更健壮地编写类。

为什么会有这种行为?就我而言,Authentication 对象永远不会为空是不正确的。

这是我的 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");
    }

    // ...
}

任何想法?谢谢!

编辑

这是调用“authenticateIfRequired()”方法的完整堆栈:

    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
    }

}
4

0 回答 0