[ ํธ๋ฌ๋ธ ์ํ ] The bean 'jwtFilter' could not be registered ์๋ฌ ํด๊ฒฐํ๊ธฐ
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์ ์ค๋ณต ๋ฑ๋กํ์ง ์๋๋ก ์ฝ๋ ์ค๊ณ๋ฅผ ๊ฐ์ ํ๊ธฐ
- ํ์ ์๋ ํด๋์ค๋ฅผ ์ ๊ฑฐํ์ฌ ์ค๋ณต ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ