AuthenticationCredentialsNotFoundException:在安全上下文中找不到身份验证对象
AuthenticationCredentialsNotFoundException: An Authentication object was not found in the Security Context
当我尝试将 JSON 有效负载从 chrome 浏览器的 POSTMAN 插件发送到暴露为 REST URL 的控制器时出现以下错误 - http://localhost:8080/services/acc/create
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/services] threw exception [Request processing failed; nested exception is org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext] with root cause
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.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at com.webadvisors.controller.HotelRestController$$EnhancerBySpringCGLIB$$e9f80d9.createHotel(<generated>)
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:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
我选择 BasicAuth 作为授权类型,并在将 JSON 负载发送到 POSTMAN 中的 REST URL 时输入了用户名和密码。
1) 控制器 class
@RestController
public class AccountRestController {
@Autowired
private AccountService accountService;
@PreAuthorize("hasAnyRole('ADMINISTRATOR')")
@RequestMapping(value= "/acc/create", method=RequestMethod.POST)
public HotelDTO createHotel(@RequestBody AccountDTO accDTO) throws Exception{
return accountService.create(accDTO);
}
}
2) 安全配置class
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@ComponentScan(basePackages = "com.freelance", scopedProxy = ScopedProxyMode.INTERFACES)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("authenticationService")
private UserDetailsService userDetailsService;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/user/**").permitAll()
.anyRequest().fullyAuthenticated();
http.httpBasic();
http.csrf().disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
}
3) Spring 安全依赖项
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
我正在 POSTMAN 中发送身份验证凭据。但为什么我会收到上述异常。
您使用 WebSecurityConfigurerAdapter
创建了一个 springSecurityFilterChain
,参见 Spring Security Reference:
The first step is to create our Spring Security Java Configuration. The configuration creates a Servlet Filter known as the springSecurityFilterChain
which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, etc) within your application.
但你没有使用它(它不在你的堆栈跟踪中)。
您必须注册 springSecurityFilterChain
。如果您有 Servlet 3.0+ 环境,请参阅 Spring Security Reference:
AbstractSecurityWebApplicationInitializer with Spring MVC
If we were using Spring elsewhere in our application we probably already had a WebApplicationInitializer
that is loading our Spring Configuration. If we use the previous configuration we would get an error. Instead, we should register Spring Security with the existing ApplicationContext
. For example, if we were using Spring MVC our SecurityWebApplicationInitializer
would look something like the following:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
This would simply only register the springSecurityFilterChain Filter for every URL in your application. After that we would ensure that WebSecurityConfig
was loaded in our existing ApplicationInitializer. For example, if we were using Spring MVC it would be added in the getRootConfigClasses()
public class MvcWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { WebSecurityConfig.class };
}
// ... other overrides ...
}
当我尝试将 JSON 有效负载从 chrome 浏览器的 POSTMAN 插件发送到暴露为 REST URL 的控制器时出现以下错误 - http://localhost:8080/services/acc/create
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/services] threw exception [Request processing failed; nested exception is org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext] with root cause
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.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
at com.webadvisors.controller.HotelRestController$$EnhancerBySpringCGLIB$$e9f80d9.createHotel(<generated>)
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:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
我选择 BasicAuth 作为授权类型,并在将 JSON 负载发送到 POSTMAN 中的 REST URL 时输入了用户名和密码。
1) 控制器 class
@RestController
public class AccountRestController {
@Autowired
private AccountService accountService;
@PreAuthorize("hasAnyRole('ADMINISTRATOR')")
@RequestMapping(value= "/acc/create", method=RequestMethod.POST)
public HotelDTO createHotel(@RequestBody AccountDTO accDTO) throws Exception{
return accountService.create(accDTO);
}
}
2) 安全配置class
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@ComponentScan(basePackages = "com.freelance", scopedProxy = ScopedProxyMode.INTERFACES)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("authenticationService")
private UserDetailsService userDetailsService;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/user/**").permitAll()
.anyRequest().fullyAuthenticated();
http.httpBasic();
http.csrf().disable();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
}
3) Spring 安全依赖项
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
我正在 POSTMAN 中发送身份验证凭据。但为什么我会收到上述异常。
您使用 WebSecurityConfigurerAdapter
创建了一个 springSecurityFilterChain
,参见 Spring Security Reference:
The first step is to create our Spring Security Java Configuration. The configuration creates a Servlet Filter known as the
springSecurityFilterChain
which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, etc) within your application.
但你没有使用它(它不在你的堆栈跟踪中)。
您必须注册 springSecurityFilterChain
。如果您有 Servlet 3.0+ 环境,请参阅 Spring Security Reference:
AbstractSecurityWebApplicationInitializer with Spring MVC
If we were using Spring elsewhere in our application we probably already had a
WebApplicationInitializer
that is loading our Spring Configuration. If we use the previous configuration we would get an error. Instead, we should register Spring Security with the existingApplicationContext
. For example, if we were using Spring MVC ourSecurityWebApplicationInitializer
would look something like the following:import org.springframework.security.web.context.*; public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { }
This would simply only register the springSecurityFilterChain Filter for every URL in your application. After that we would ensure that
WebSecurityConfig
was loaded in our existing ApplicationInitializer. For example, if we were using Spring MVC it would be added in thegetRootConfigClasses()
public class MvcWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { WebSecurityConfig.class }; } // ... other overrides ... }