我在 Spring Boot 项目中使用 Spring Data Rest 和 Spring Security 。
我有一个安全注释,允许ADMIN
个用户在类级别执行所有方法:@PreAuthorize("hasAuthority('ADMIN')")
。
我只想要这个存储库中的一个方法(findByPersonalNumber
),它在Spring安全身份验证过程中使用(参见UserDetailsService
),没有任何安全性。
@RepositoryRestResource(collectionResourceRel = "users", path = "users")
@PreAuthorize("hasAuthority('ADMIN')")
public interface UserRepository extends CrudRepository<User, Integer> {
@PreAuthorize("permitAll()")
@RestResource(exported = false)
Optional<User> findByPersonalNumber(String personalNumber);
}
@Service
public class AuthenticationService implements UserDetailsService {
private final UserRepository userRepository;
@Inject
public AuthenticationService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.getByPersonalNumber(username);
return new CurrentUser(user);
}
}
当我尝试执行使用存储库的方法findByPersonalNumber
的身份验证过程时,我有这种异常:
2015-08-13 10:11:02.989 DEBUG 1654 --- [nio-8080-exec-4] o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2015-08-13 10:11:11.193 DEBUG 1654 --- [nio-8080-exec-4] .PrePostAnnotationSecurityMetadataSource : @org.springframework.security.access.prepost.PreAuthorize(value=permitAll()) found on specific method: public final java.util.Optional com.sun.proxy.$Proxy116.findByPersonalNumber(java.lang.String)
2015-08-13 10:11:11.193 DEBUG 1654 --- [nio-8080-exec-4] m.DelegatingMethodSecurityMetadataSource : Caching method [CacheKey[com.sun.proxy.$Proxy116; public abstract java.util.Optional xxx.repositories.UserRepository.findByPersonalNumber(java.lang.String)]] with attributes [[authorize: 'permitAll()', filter: 'null', filterTarget: 'null']]
2015-08-13 10:11:11.193 DEBUG 1654 --- [nio-8080-exec-4] .PrePostAnnotationSecurityMetadataSource : @org.springframework.security.access.prepost.PreAuthorize(value=permitAll()) found on specific method: public abstract java.util.Optional com.dassault_systemes.diy.repositories.UserRepository.findByPersonalNumber(java.lang.String)
2015-08-13 10:11:11.193 DEBUG 1654 --- [nio-8080-exec-4] m.DelegatingMethodSecurityMetadataSource : Caching method [CacheKey[org.springframework.data.jpa.repository.support.SimpleJpaRepository; public abstract java.util.Optional xxx.repositories.UserRepository.findByPersonalNumber(java.lang.String)]] with attributes [[authorize: 'permitAll()', filter: 'null', filterTarget: 'null']]
2015-08-13 10:11:11.193 DEBUG 1654 --- [nio-8080-exec-4] o.s.s.a.i.a.MethodSecurityInterceptor : Secure object: ReflectiveMethodInvocation: public abstract java.util.Optional xxx.repositories.UserRepository.findByPersonalNumber(java.lang.String); target is of class [com.sun.proxy.$Proxy116]; Attributes: [[authorize: 'permitAll()', filter: 'null', filterTarget: 'null']]
2015-08-13 10:11:11.194 DEBUG 1654 --- [nio-8080-exec-4] .s.a.DefaultAuthenticationEventPublisher : No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException
2015-08-13 10:11:11.195 ERROR 1654 --- [nio-8080-exec-4] w.a.UsernamePasswordAuthenticationFilter : An internal error occurred while trying to authenticate the user.
org.springframework.security.authentication.InternalAuthenticationServiceException: An Authentication object was not found in the SecurityContext
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:110)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:92)
[...]
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:339)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:198)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:60)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy119.findByPersonalNumber(Unknown Source)
at com.dassault_systemes.diy.service.UserServiceImpl.getByPersonalNumber(UserServiceImpl.java:37)
at com.dassault_systemes.diy.service.AuthenticationService.loadUserByUsername(AuthenticationService.java:35)
我还尝试使用@PreAuthorize
注释isAnonymous()
注释而没有更好的结果。