问题
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
SecurityContextwith 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