【问题标题】:Spring boot Security Config - authenticationManager must be specifiedSpring boot Security Config - 必须指定 authenticationManager
【发布时间】:2015-09-30 19:55:57
【问题描述】:

这是我的主要应用程序配置

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class)
                .banner((environment, aClass,  printStream) ->
                        System.out.println(stringBanner()))
                .run();
    }
}

这是我的 Spring Security 应用程序配置。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private WebServiceAuthenticationEntryPoint unauthorizedHandler;

    @Autowired
    private TokenProcessingFilter authTokenProcessingFilter;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf()
                .disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // Restful hence stateless
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(unauthorizedHandler) // Notice the entry point
                .and()
                .addFilter(authTokenProcessingFilter) // Notice the filter
                .authorizeRequests()
                .antMatchers("/resources/**", "/api/auth")
                .permitAll()
                .antMatchers("/greeting")
                .hasRole("USER");
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("user")
                .password("password")
                .roles("USER");
    }
}

这是我的 TokenProcessingFilter,它为我的自定义身份验证过滤器扩展了 UsernamePasswordAuthenticationFilter

@Component
public class TokenProcessingFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = this.getAsHttpRequest(request);
        String authToken = this.extractAuthTokenFromRequest(httpRequest);
        String userName = TokenUtils.getUserNameFromToken(authToken);
        if (userName != null) {/*
            UserDetails userDetails = userDetailsService.loadUserByUsername(userName);*/
            UserDetails userDetails = fakeUserDetails();
            if (TokenUtils.validateToken(authToken, userDetails)) {
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
                SecurityContextHolder.getContext().setAuthentication(authentication);
                Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            }
        }
        chain.doFilter(request, response);
    }

    private HttpServletRequest getAsHttpRequest(ServletRequest request){
        if (!(request instanceof HttpServletRequest)) {
            throw new RuntimeException("Expecting an HTTP request");
        }
        return (HttpServletRequest) request;
    }


    private String extractAuthTokenFromRequest(HttpServletRequest httpRequest) {
        /* Get token from header */
        String authToken = httpRequest.getHeader("x-auth-token");
        /* If token not found get it from request parameter */
        if (authToken == null) {
            authToken = httpRequest.getParameter("token");
        }
        return authToken;
    }

    private UserDetails fakeUserDetails(){
        UsernamePasswordAuthenticationToken authenticationToken = new
                UsernamePasswordAuthenticationToken("user","password");

        List<SimpleGrantedAuthority> auth= new ArrayList<>();
        auth.add(new SimpleGrantedAuthority("USER"));
        return  new User("user","password",auth);
    }
}

但是在运行应用程序时,我遇到了这个异常消息。我错过了什么?

运行时发生异常。空:调用目标异常: 无法启动嵌入式容器;嵌套异常是 org.springframework.boot.context.embedded.EmbeddedServletContainerException: 无法启动嵌入式 Tomcat:使用名称创建 bean 时出错 文件中定义的“tokenProcessingFilter” [C:\Users\kyel\projects\app\target\classes\org\app\testapp\security\TokenProcessingFilter.class]: 调用 init 方法失败;嵌套异常是 java.lang.IllegalArgumentException: authenticationManager 必须是 指定

【问题讨论】:

    标签: java spring spring-security spring-boot


    【解决方案1】:

    您需要在TokenProcessingFilter 上设置AuthenticationManager。不要在 TokenProcessingFilter 上使用 @Component,只需在 SecurityConfig 中创建它。

    @Bean
    TokenProcessingFilter tokenProcessingFilter() {
      TokenProcessingFilter tokenProcessingFilter = new TokenProcessingFilter();
      tokenProcessingFilter.setAuthenticationManager(authenticationManager());
      return tokenProcessingFilter;
    }
    

    protected void configure(HttpSecurity http) throws Exception {
      ...
      .addFilter(tokenProcessingFilter())
    

    【讨论】:

    • 为什么要创建一个bean?如果然后显式调用该方法?
    【解决方案2】:

    为了保留组件注释,您必须从 AbstractAuthenticationProcessingFilter 覆盖 setAuthenticationManager 并自动装配参数,如下所示:

    @Component
    public class TokenProcessingFilter extends UsernamePasswordAuthenticationFilter {
    
        //...
    
        @Override
        @Autowired
        public void setAuthenticationManager(AuthenticationManager authenticationManager) {
            super.setAuthenticationManager(authenticationManager);
        }
    
        //...
    
    }
    

    【讨论】:

      猜你喜欢
      • 2016-03-17
      • 2018-12-24
      • 2014-12-06
      • 2011-01-20
      • 2015-12-28
      • 2020-04-29
      • 2020-10-27
      • 2012-02-03
      • 2017-11-27
      相关资源
      最近更新 更多