๐Ÿ’ป ํ”„๋กœ์ ํŠธ/ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

[ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ… ] The bean 'jwtFilter' could not be registered ์—๋Ÿฌ ํ•ด๊ฒฐํ•˜๊ธฐ

carrot0911 2025. 1. 27. 09:27

Spring ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋‹ค๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ ๋งˆ์ฃผํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค.

The bean 'jwtFilter', defined in class path resource [org/example/expert/config/FilterConfig.class], could not be registered. A bean with that name has already been defined in file [/Users/t2023-m0071/IdeaProjects/spring-plus/build/classes/java/main/org/example/expert/config/JwtFilter.class] and overriding is disabled.


๋ฌธ์ œ ์ƒํ™ฉ

์œ„ ์—๋Ÿฌ๋Š” JwtFilter.class์—์„œ ์ด๋ฏธ Bean์œผ๋กœ ๋“ฑ๋กํ•œ ์ƒํƒœ์—์„œ, FilterConfig.class์—์„œ๋„ ๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ Bean์„ ๋“ฑ๋กํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋ฉด์„œ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ์ด๋‹ค.
Spring์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ™์€ ์ด๋ฆ„์˜ Bean์„ ์ค‘๋ณตํ•ด์„œ ๋“ฑ๋กํ•  ์ˆ˜ ์—†๋„๋ก ์„ค์ •๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ด ๊ฒฝ์šฐ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.


๋ฌธ์ œ ์›์ธ ๋ถ„์„

 Spring์—์„œ Bean์„ ๋“ฑ๋กํ•  ๋•Œ ์ค‘๋ณต ๋“ฑ๋ก ๋ฐฉ์ง€ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•œ๋‹ค.

  • JwtFilter.class์—์„œ ์ด๋ฏธ @Component ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์„œ Bean์œผ๋กœ ๋“ฑ๋กํ•œ ์ƒํƒœ์ด๋‹ค.
  • ๊ทธ๋Ÿฌ๋‚˜ FilterConfig.class์—์„œ ๊ฐ™์€ ์ด๋ฆ„์œผ๋กœ Bean์„ ๋˜ ๋“ฑ๋กํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋ฉด์„œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ–ˆ๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

์ค‘๋ณต์œผ๋กœ ๋“ฑ๋ก๋œ Bean ์ค‘ ํ•˜๋‚˜๋ฅผ ์ œ๊ฑฐํ•ด์•ผ ํ•œ๋‹ค.
์ด ๊ฒฝ์šฐ์—๋Š” FilterConfig๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชฉ์ ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š๋‹ค๋ฉด, FilterConfig๋ฅผ ์‚ญ์ œํ•˜๋Š” ๊ฒƒ์ด ์ ํ•ฉํ•˜๋‹ค.
์‹ค์ œ๋กœ FilterConfig.class๋ฅผ ์‚ญ์ œํ•˜๊ณ  application์„ ๋‹ค์‹œ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋๋‹ค.


ํ•ด๊ฒฐ ๊ณผ์ •

  • FilterConfig.class์˜ ์—ญํ•  ํ™•์ธ
    • JwtFilter ์™ธ์— ๋‹ค๋ฅธ ํ•„๋Ÿฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์—ญํ• ์ด ์—†๋‹ค๋ฉด ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์‚ญ์ œํ•ด๋„ ๋ฌธ์ œ์—†๋‹ค.
  • FilterConfig.class ์‚ญ์ œ
    • ํ”„๋กœ์ ํŠธ์—์„œ FilterConfig.class ํŒŒ์ผ์„ ์ œ๊ฑฐํ–ˆ๋‹ค.
  • application ์žฌ์‹คํ–‰
    • ์—๋Ÿฌ ์—†์ด ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.

์ฐธ๊ณ  ์ฝ”๋“œ

JwtFilter.class

๋”๋ณด๊ธฐ
@Slf4j
@RequiredArgsConstructor
public class JwtFilter implements Filter {

    private final JwtUtil jwtUtil;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String url = httpRequest.getRequestURI();

        if (url.startsWith("/auth")) {
            chain.doFilter(request, response);
            return;
        }

        String bearerJwt = httpRequest.getHeader("Authorization");

        if (bearerJwt == null) {
            // ํ† ํฐ์ด ์—†๋Š” ๊ฒฝ์šฐ 400์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
            httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "JWT ํ† ํฐ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.");
            return;
        }

        String jwt = jwtUtil.substringToken(bearerJwt);

        try {
            // JWT ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์™€ claims ์ถ”์ถœ
            Claims claims = jwtUtil.extractClaims(jwt);
            if (claims == null) {
                httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "์ž˜๋ชป๋œ JWT ํ† ํฐ์ž…๋‹ˆ๋‹ค.");
                return;
            }

            UserRole userRole = UserRole.valueOf(claims.get("userRole", String.class));

            httpRequest.setAttribute("userId", Long.parseLong(claims.getSubject()));
            httpRequest.setAttribute("email", claims.get("email"));
            httpRequest.setAttribute("nickname", claims.get("nickname"));
            httpRequest.setAttribute("userRole", claims.get("userRole"));

            if (url.startsWith("/admin")) {
                // ๊ด€๋ฆฌ์ž ๊ถŒํ•œ์ด ์—†๋Š” ๊ฒฝ์šฐ 403์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
                if (!UserRole.ADMIN.equals(userRole)) {
                    httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "๊ด€๋ฆฌ์ž ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.");
                    return;
                }
                chain.doFilter(request, response);
                return;
            }

            chain.doFilter(request, response);
        } catch (SecurityException | MalformedJwtException e) {
            log.error("Invalid JWT signature, ์œ ํšจํ•˜์ง€ ์•Š๋Š” JWT ์„œ๋ช… ์ž…๋‹ˆ๋‹ค.", e);
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "์œ ํšจํ•˜์ง€ ์•Š๋Š” JWT ์„œ๋ช…์ž…๋‹ˆ๋‹ค.");
        } catch (ExpiredJwtException e) {
            log.error("Expired JWT token, ๋งŒ๋ฃŒ๋œ JWT token ์ž…๋‹ˆ๋‹ค.", e);
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "๋งŒ๋ฃŒ๋œ JWT ํ† ํฐ์ž…๋‹ˆ๋‹ค.");
        } catch (UnsupportedJwtException e) {
            log.error("Unsupported JWT token, ์ง€์›๋˜์ง€ ์•Š๋Š” JWT ํ† ํฐ ์ž…๋‹ˆ๋‹ค.", e);
            httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "์ง€์›๋˜์ง€ ์•Š๋Š” JWT ํ† ํฐ์ž…๋‹ˆ๋‹ค.");
        } catch (Exception e) {
            log.error("Internal server error", e);
            httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

์‚ญ์ œ๋œ FilterConfig.class

๋”๋ณด๊ธฐ
@Configuration
@RequiredArgsConstructor
public class FilterConfig {

    private final JwtUtil jwtUtil;

    @Bean
    public FilterRegistrationBean<JwtFilter> jwtFilter() {
        FilterRegistrationBean<JwtFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new JwtFilter(jwtUtil));
        registrationBean.addUrlPatterns("/*"); // ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•  URL ํŒจํ„ด์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

        return registrationBean;
    }
}

๊ฒฐ๋ก 

Spring์—์„œ ๋™์ผํ•œ ์ด๋ฆ„์˜ Bean์„ ์ค‘๋ณต ๋“ฑ๋กํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์œ„์™€ ๊ฐ™์ด ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๋ ‡๊ฒŒ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Bean์ด ์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ
  • ๊ฐ™์€ ์ด๋ฆ„์œผ๋กœ Bean์„ ์ค‘๋ณต ๋“ฑ๋กํ•˜์ง€ ์•Š๋„๋ก ์ฝ”๋“œ ์„ค๊ณ„๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ
  • ํ•„์š” ์—†๋Š” ํด๋ž˜์Šค๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ์ค‘๋ณต ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ