AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext

浪子不回头ぞ 提交于 2020-01-02 07:42:12

问题


I have this implementation of a login function on my server following this post basically:

@Transactional
public void login(String userId, String password) {

    LOGGER.debug("Login for " + userId);

    User user = new User(userId, password, true, true, true, true, new ArrayList<GrantedAuthority>());

    Authentication auth = new UsernamePasswordAuthenticationToken(user, password,
            new ArrayList<GrantedAuthority>());

    try {
        auth = this.authenticationProvider.authenticate(auth);
    } catch(BadCredentialsException e) {
        LOGGER.debug("Bad credentials ..");
        throw new RuntimeException(e.getMessage());
    }

    LOGGER.debug("User successfully authenticated [userId="+userId+"]");

    SecurityContext sc = new SecurityContextImpl();
    sc.setAuthentication(auth);

    SecurityContextHolder.setContext(sc);       
}

This appears to work so far without any troubles. However, if I execute this request right after login

@PreAuthorize("hasPermission('ADMIN')")
public void test(String msg) {
    LOGGER.debug("test: " + msg);
}

the result is this exception here:

Caused by: org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:378)
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:222)
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:64)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
    at com.mz.server.web.service.LoginService$$EnhancerBySpringCGLIB$$caf0e62d_2.test(<generated>)
    at com.mz.server.web.servlet.LoginServletImpl.test(LoginServletImpl.java:99)

Reading about SecurityContextHolder.setContext() it says:

Associates a new SecurityContext with the current thread of execution.

so I guess my problem here is that I don't understand how Spring can recall a user that just logged into my system and now wants to proceed with authenticated request.

And why am I not just getting redirected to /login?


Spring context:

<!-- //////////////////////////////////////////////////////////////////////////////// -->
<!-- // BEGIN Spring Security -->

<sec:http auto-config="true" use-expressions="true"/>

<bean id="httpSessionSecurityContextRepository" class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
    <property name='allowSessionCreation' value='false' />
</bean>

<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
    <constructor-arg ref="httpSessionSecurityContextRepository" />
</bean>

<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
    <constructor-arg>
        <list>
            <sec:filter-chain pattern="/**" filters="securityContextPersistenceFilter" />
        </list>
    </constructor-arg>
</bean>

<bean id="authenticationListener" class="com.mz.server.web.auth.CustomAuthenticationListener"/>

<bean id="authenticationProvider" class="com.mz.server.web.auth.CustomAuthenticationProvider"/>

<bean id="userDetailsService" class="com.mz.server.web.service.CustomUserDetailsService"/>

<sec:authentication-manager alias="authenticationManager">
    <sec:authentication-provider ref="authenticationProvider"/>
</sec:authentication-manager>

<sec:global-method-security 
    authentication-manager-ref="authenticationManager"
    pre-post-annotations="enabled"/>

<!-- // END Spring Security -->
<!-- //////////////////////////////////////////////////////////////////////////////// -->

web.xml

<!-- //////////////////////////////////////////////////////////////////////////////// -->
<!-- // BEGIN Filters -->

<!-- Spring Security -->

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/**</url-pattern>
</filter-mapping>

<!-- // END FILTERS -->
<!-- //////////////////////////////////////////////////////////////////////////////// -->

回答1:


I know your pain, I had a hell of a time figuring out Spring Security. Really debating whether it was worth it. But you probably need to add the SecurityContextPersistenceFilter. This will automatically add your Credentials to the SecurityContext using the HttpSession from the JSessionID typically. I have a custom authentication handler so there is some extra parts to my code that are not relevant but I think this should probably get you pointed in the right direction.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sec="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">


<bean id="httpSessionSecurityContextRepository"
    class='org.springframework.security.web.context.HttpSessionSecurityContextRepository'>
    <property name='allowSessionCreation' value='false' />
</bean>

<bean id="securityContextPersistenceFilter"
    class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
    <constructor-arg ref="httpSessionSecurityContextRepository" />
</bean>

<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
    <constructor-arg>
        <list>
            <sec:filter-chain pattern="/rest/**"
                filters="securityContextPersistenceFilter" />
        </list>
    </constructor-arg>
</bean>

<sec:global-method-security
    authentication-manager-ref="authenticationManager"
    secured-annotations="enabled" />


来源:https://stackoverflow.com/questions/34121873/authenticationcredentialsnotfoundexception-an-authentication-object-was-not-fou

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!