我有一个奇怪的问题,在我登录后,我可以发出一个请求,之后每个后续请求都会抛出一个Spring AuthenticationCredentialsNotFoundException
。我不知道为什么会这样。
在我的LoginService
中,我使用我的注入AdminAuthenticationProvider
将用户登录到:
public class LoginService {
private AuthenticationProvider adminAuthenticationProvider;
public LoginService(DSLContext ctx, AuthenticationProvider adminAuthenticationProvider) {
this.adminAuthenticationProvider = adminAuthenticationProvider;
}
@Transactional
public void login(String userId, String password) {
CustomUserDetails user = new CustomUserDetails(userId, password, true, true, true, true, new ArrayList<GrantedAuthority>());
Authentication auth = new UsernamePasswordAuthenticationToken(user, password,
new ArrayList<GrantedAuthority>());
try {
auth = this.adminAuthenticationProvider.authenticate(auth);
} catch(BadCredentialsException e) {
throw e;
}
SecurityContext sc = new SecurityContextImpl();
sc.setAuthentication(auth);
SecurityContextHolder.setContext(sc);
}
}
AdminAuthenticationProvider
实施:
public class AdminAuthenticationProvider implements AuthenticationProvider {
private RestaurantAdminRepository restaurantAdminRepository;
public AdminAuthenticationProvider(DSLContext ctx) {
this.restaurantAdminRepository = new RestaurantAdminRepository(ctx);
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
CustomUserDetails user = (CustomUserDetails) authentication.getPrincipal();
List<String> roles = new ArrayList<>();
roles.add("ROLE_ADMIN");
Authentication customAuthentication = new CustomUserAuthentication(roles, authentication);
customAuthentication.setAuthenticated(true);
return customAuthentication;
}
@Override
public boolean supports(Class<? extends Object> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
如您所见,这里没有真正检查过,用户只是登录了。
但是,之后我总是得到例外。目前我只使用isAuthenticated()
。
@PreAuthorize("isAuthenticated()")
public List<StoreDTO> getAvailableStores() {
// ..
return result;
}
这可能是什么问题?
这是我的配置 applicationContext-spring-acl.xml
<?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:security="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd">
<!-- Imports -->
<import resource="applicationContext-jooq.xml"/>
<!-- See 15.3.2 Built-In Expression @http://static.springsource.org/spring-security/site/docs/3.0.x/reference/el-access.html#el-permission-evaluator -->
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<!-- To use hasPermission() in expressions, configure a PermissionEvaluator -->
<property name="permissionEvaluator" ref="permissionEvaluator" />
<property name="roleHierarchy" ref="roleHierarchy" />
</bean>
<bean class="com.mahlzeit.server.web.auth.permission.CustomAclPermissionEvaluator" id="permissionEvaluator">
<constructor-arg ref="aclService" />
</bean>
<!-- Declare an acl service -->
<bean class="org.springframework.security.acls.jdbc.JdbcMutableAclService" id="aclService">
<constructor-arg ref="dataSource" />
<constructor-arg ref="lookupStrategy" />
<constructor-arg ref="aclCache" />
</bean>
<!-- Declare a lookup strategy -->
<bean id="lookupStrategy"
class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource" />
<constructor-arg ref="aclCache" />
<constructor-arg ref="aclAuthorizationStrategy" />
<constructor-arg ref="auditLogger" />
</bean>
<!-- Declare an acl cache -->
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:shared="true"/>
</property>
<property name="cacheName" value="aclCache" />
</bean>
</constructor-arg>
<constructor-arg>
<bean
class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger" />
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg>
<bean
class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean
class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ACL_ADMIN" />
</bean>
</list>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<!-- Declare an acl authorization strategy -->
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean
class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMIN" />
</bean>
<bean
class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMIN" />
</bean>
<bean
class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ADMIN" />
</bean>
</list>
</constructor-arg>
</bean>
<!-- Declare an audit logger -->
<bean id="auditLogger"
class="org.springframework.security.acls.domain.ConsoleAuditLogger" />
<!-- http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/access/hierarchicalroles/RoleHierarchyImpl.html -->
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ADMIN > ROLE_USER
ROLE_USER > ROLE_VISITOR
</value>
</property>
</bean>
<sec:global-method-security authentication-manager-ref="authenticationManager" pre-post-annotations="enabled">
<sec:expression-handler ref="expressionHandler"/>
</sec:global-method-security>
</beans>
这是 applicationContext-spring-security.xml
<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-4.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd"
>
<!-- Imports -->
<import resource="applicationContext-spring-acl.xml"/>
<sec:http pattern="/**" 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.mahlzeit.server.web.auth.CustomAuthenticationListener"/>
<bean id="adminAuthenticationProvider" class="com.mahlzeit.server.web.auth.AdminAuthenticationProvider">
<constructor-arg ref="dslContext" />
</bean>
<bean id="userDetailsService" class="com.mahlzeit.server.web.service.CustomUserDetailsService"/>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="adminAuthenticationProvider"/>
</sec:authentication-manager>
</beans>
[http-bio-8080-exec-3] DEBUG com.mz.server.web.servlet.StoreServletImpl - Requested available stores.
[http-bio-8080-exec-3] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public java.util.List com.mz.server.web.service.StoreService.getAvailableStores(); target is of class [com.mz.server.web.service.StoreService]; Attributes: [[authorize: 'isAuthenticated()', filter: 'null', filterTarget: 'null']]
[http-bio-8080-exec-3] TRACE org.springframework.context.support.ClassPathXmlApplicationContext - Publishing event in org.springframework.context.support.ClassPathXmlApplicationContext@19c3e3e: org.springframework.security.access.event.AuthenticationCredentialsNotFoundEvent[source=ReflectiveMethodInvocation: public java.util.List com.mz.server.web.service.RestaurantService.getAvailableStores(); target is of class [com.mz.server.web.service.StoreService]]
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:655)
at com.mahlzeit.server.web.service.RestaurantService$$EnhancerBySpringCGLIB$$9012bad4_3.getAvailableRestaurants(<generated>)
at com.mahlzeit.server.web.servlet.RestaurantServletImpl.getAvailableRestaurants(RestaurantServletImpl.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:587)
... 25 more
答案 0 :(得分:1)
更改这些行:
SecurityContext sc = new SecurityContextImpl();
sc.setAuthentication(auth);
SecurityContextHolder.setContext(sc);
为:
SecurityContextHolder.getContext().setAuthentication(auth);
如果HttpSessionSecurityContextRepository
用法,您希望将此auth对象绑定到整个会话not only to the request。
答案 1 :(得分:0)
我不知道您的LoginService如何与Spring Security集成。我会考虑自定义用户详细信息服务:
public class CustomUserDetailsService extends JdbcUserDetailsManager implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
然后将其集成到您的SecurityConfig中:
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
....
auth.userDetailsService(customUserDetailsService()).passwordEncoder(passwordEncoder);
auth.authenticationProvider(authenticationProvider);
}