java - AuthenticationCredentialsNotFoundException : An Authentication object was not found in the Security Context

标签 java spring spring-security spring-java-config

当我尝试将 JSON 有效负载从 Chrome 浏览器的 POSTMAN 插件发送到公开为 REST URL 的 Controller 时,出现以下错误 - 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) Controller 类

@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)安全配置类

@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 ...
}

关于java - AuthenticationCredentialsNotFoundException : An Authentication object was not found in the Security Context,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41710743/

相关文章:

JavaFX TreeView setRoot 导致异常

java - Spring Controller 被调用但返回 404

spring-security - 退出时 Cookie 从浏览器中删除(Spring Security 3.1)?

java - 如何使用 Gradle 构建 Apache Spark?

java - 如何在动态加载的 jar 中模拟方法

java - 使用 proguard 进行 RCP 插件混淆

java - Apache Camel从cxfrs到activemq队列的路由问题

java - 返回带有类型的 spring bean

java - Spring 启动 OAuth2 : How to retrieve user token info details

java - 在 Spring Boot 中注入(inject) Autowiring 依赖项的问题