我正在教程中学习安全配置,并将转到JWT认证material .AuthenticationManager中存在循环依赖项错误.我判断了所有的东西,但我看不出我做错了什么.我希望你们能帮我解决这个问题.

..>bookcatalog>config>SecurityConfig.class

package com.bluedev.bookcatalog.config;

import com.bluedev.bookcatalog.security.filter.UsernamePasswordAuthenticationFilter;
import com.bluedev.bookcatalog.security.provider.UsernamePasswordAuthProvider;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

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

    private static final String V1_URL = "/v1/**";
    private static final String V2_URL = "/v2/**";

    @Autowired
    private AuthenticationSuccessHandler successHandler;

    @Autowired
    private AuthenticationFailureHandler failureHandler;

    @Autowired
    private UsernamePasswordAuthProvider usernamePasswordAuthProvider;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private ObjectMapper objectMapper;

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //auth.userDetailsService(appUserService).passwordEncoder(appConfig.passwordEncoder());
        auth.authenticationProvider(usernamePasswordAuthProvider);
    }

    protected UsernamePasswordAuthenticationFilter buildUsernamePasswordAuthFilter(String loginEntryPoint){
        UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(loginEntryPoint, successHandler, failureHandler, objectMapper);
        filter.setAuthenticationManager(authenticationManager);

        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers(V1_URL, V2_URL).authenticated()
                .and()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilterBefore(buildUsernamePasswordAuthFilter("/v1/login"), org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.class);
    }
}

..>bookcatalog>security>filter>UsernamePasswordAuthenticationFilter.java

package com.bluedev.bookcatalog.security.filter;

import com.bluedev.bookcatalog.dto.LoginRequestDTO;
import com.bluedev.bookcatalog.exception.BadRequestException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private final AuthenticationSuccessHandler successHandler;
    private final AuthenticationFailureHandler failureHandler;
    private final ObjectMapper objectMapper;


    public UsernamePasswordAuthenticationFilter(String defaultFilterProcessesUrl, AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler, ObjectMapper objectMapper) {
        super(defaultFilterProcessesUrl);
        this.successHandler = successHandler;
        this.failureHandler = failureHandler;
        this.objectMapper = objectMapper;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        LoginRequestDTO dto = objectMapper.readValue(request.getReader(), LoginRequestDTO.class);

        if(StringUtils.isBlank(dto.getUsername()) || StringUtils.isBlank(dto.getPassword())){
            throw new BadRequestException("username & password must be provided.");
        }

        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(dto.getUsername(), dto.getPassword());

        return this.getAuthenticationManager().authenticate(token);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        this.successHandler.onAuthenticationSuccess(request, response, authResult);
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        this.failureHandler.onAuthenticationFailure(request, response, failed);
    }

}

..>bookcatalog>security>provider>UsernamePasswordAuthProvider.java

package com.bluedev.bookcatalog.security.provider;

import com.bluedev.bookcatalog.service.AppUserService;
import lombok.AllArgsConstructor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@AllArgsConstructor
@Component
public class UsernamePasswordAuthProvider implements AuthenticationProvider {

    private final AppUserService appUserService;
    private final PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = (String) authentication.getPrincipal();
        String password = (String) authentication.getCredentials();

        UserDetails appUser = appUserService.loadUserByUsername(username);

        if(!passwordEncoder.matches(password, appUser.getPassword())){
            throw new BadCredentialsException("invalid.username.password");
        }

        return new UsernamePasswordAuthenticationToken(appUser, null, appUser.getAuthorities());
    }


    @Override
    public boolean supports(Class<?> authentication) {
        return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }
}

..>bookcatalog/security/handler/UsernamePasswordAuthSuccessHandler.java

package com.bluedev.bookcatalog.security.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@AllArgsConstructor
@Component
public class UsernamePasswordAuthSuccessHandler implements AuthenticationSuccessHandler {

    private final ObjectMapper objectMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("result", "SUCCESS");

        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);

        objectMapper.writeValue(response.getWriter(), resultMap);
    }
}

..>bookcatalog/security/handler/UsernamePasswordAuthFailureHandler.java

package com.bluedev.bookcatalog.security.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@AllArgsConstructor
@Component
public class UsernamePasswordAuthFailureHandler implements AuthenticationFailureHandler {

    private final ObjectMapper objectMapper;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("result", "FAILURE");

        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);

        objectMapper.writeValue(response.getWriter(), resultMap);
    }
}

Error Result


2022-06-17 18:31:06.226 ERROR 18092 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌──->──┐
|  securityConfig (field private org.springframework.security.authentication.AuthenticationManager com.bluedev.bookcatalog.config.SecurityConfig.authenticationManager)
└──<-──┘


Action:

Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.


Process finished with exit code 1

推荐答案

SecurityConfig中删除以下行

@Autowired
private AuthenticationManager authenticationManager;  

并将buildUsernamePasswordAuthFilter函数修改为authenticationManagerBean()函数

protected UsernamePasswordAuthenticationFilter buildUsernamePasswordAuthFilter(String loginEntryPoint){
    UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter(loginEntryPoint, successHandler, failureHandler, objectMapper);
    filter.setAuthenticationManager(authenticationManagerBean());

    return filter;
}

Java相关问答推荐

Java同步小服务器

try 使用Java 9或更高版本对特殊对象图进行解析时出现NullPointerException

在模拟超类中设置非setter属性的值

由于 list 中的权限错误,Android未生成

Jenv-相同的Java版本,但带有前缀

在JDK 1.8源代码中,为什么使用A-B 0来确定哪个更大,而不是A B?

从ActiveMQ Classic迁移到ActiveMQ Artemis需要进行哪些客户端更改?

Java Mooc.fi Part 12_01.Hideout -返回和删除方法

如何在构建Gradle项目时排除com.google.guava依赖项的一个变体

Spring动态反序列化JSON可以是列表,也可以只是一个对象

在应用getCellFormula()时,Excel引用中的文件名始终为";[1]";使用Apache POI()

循环不起作用只有第一个元素重复

基于Java中mm/dd/yy格式的最近日期对数组列表进行排序

Java System.getProperty在哪里检索user.home?

控制器建议异常处理

整数->;双取消框,但双->;int不';t开箱.为什么?

保持标题窗格的箭头可见,即使设置为不可折叠

如何在Selenium上继续使用最新的WebDriver版本

使用原子整数的共享计数器并发增量

在输入端没有可行的替代方案'; Select *';