728x90
반응형
🤣 문제 상황
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
jwtAuthenticationFilter defined in file [C:\Users\admin\IdeaProjects\exercise_board\build\classes\java\main\org\board\exercise_board\user\Security\JwtAuthenticationFilter.class]
┌─────┐
| jwtTokenProvider defined in file [C:\Users\admin\IdeaProjects\exercise_board\build\classes\java\main\org\board\exercise_board\user\Security\JwtTokenProvider.class]
↑ ↓
| userService defined in file [C:\Users\admin\IdeaProjects\exercise_board\build\classes\java\main\org\board\exercise_board\user\service\UserService.class]
└─────┘
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
순환참조가 발생해서 process가 종료되는 문제가 발생했다.
⚡문제 발생 코드
JwtTokenProvider.java
@Component
@Slf4j
public class JwtTokenProvider {
/**
생략
**/
private final Key key;
private final UserService userService; // 문제 발생하는 객체
public JwtTokenProvider(
@Value("${jwt.secretKey}") String secretKey
,UserService userService
) {
this.userService = userService;
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
this.key = Keys.hmacShaKeyFor(keyBytes);
}
// Jwt 토큰을 복호화하여 토큰에 들어있는 인증 정보를 꺼내는 메서드
public Authentication getAuthentication(String accessToken) {
// Jwt 토큰 복호화
Claims claims = parseClaims(accessToken);
if (claims.get(AUTHORITIES_KEY) == null) {
throw new RuntimeException("권한 정보가 없는 토큰입니다.");
}
// 해당 사용자의 권한 정보 가져오기
Collection<? extends GrantedAuthority> authorities =
Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
// 문제 발생 !!!!!
// UserDetails 객체 생성해서 Authentication 리턴
UserDetails principal = userService.loadUserByUsername(claims.getSubject());
return new UsernamePasswordAuthenticationToken(
principal, accessToken, authorities);
}
/**
생략
**/
}
UserService.java
package org.board.exercise_board.user.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.board.exercise_board.post.exception.PostCustomException;
import org.board.exercise_board.post.exception.PostErrorCode;
import org.board.exercise_board.user.Security.JwtTokenProvider;
import org.board.exercise_board.user.domain.Form.SignUpForm;
import org.board.exercise_board.user.domain.model.JwtToken;
import org.board.exercise_board.user.domain.model.User;
import org.board.exercise_board.user.domain.repository.UserRepository;
import org.board.exercise_board.user.exception.CustomException;
import org.board.exercise_board.user.exception.ErrorCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
@Slf4j
public class UserService implements UserDetailsService {
/**
생략
**/
// 문제 발생 !!!
private final JwtTokenProvider jwtTokenProvider;
// 문제 발생 !!!
public JwtToken signin(String loginId, String password) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
loginId, password);
Authentication authentication = authenticationManagerBuilder.getObject()
.authenticate(authenticationToken);
JwtToken token = jwtTokenProvider.createToken(authentication);
return token;
}
/**
생략
**/
@Override
public UserDetails loadUserByUsername(String loginId) throws UsernameNotFoundException {
log.info(" --- 회원 정보 찾기, {} --- ", loginId);
return userRepository.findByLoginId(loginId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_USER));
}
}
👌 문제 원인
JwtTokenProvider 에서는 UserService를 참조하고 UserService에서는 JwtTokenProvider을 참조하고 있어서 무한 순환이 되고 있었다.
따라서 JwtTokenProvider에서 UserService 사용을 하지 않도록 했더니 해결이 되었다.
😁 해결 코드
@Component
@Slf4j
public class JwtTokenProvider {
/**
생략
**/
private final Key key;
public JwtTokenProvider(
@Value("${jwt.secretKey}") String secretKey
// ,UserService userService -> 삭제
) {
this.userService = userService; // -> 삭제
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
this.key = Keys.hmacShaKeyFor(keyBytes);
}
// Jwt 토큰을 복호화하여 토큰에 들어있는 인증 정보를 꺼내는 메서드
public Authentication getAuthentication(String accessToken) {
// Jwt 토큰 복호화
Claims claims = parseClaims(accessToken);
if (claims.get(AUTHORITIES_KEY) == null) {
throw new RuntimeException("권한 정보가 없는 토큰입니다.");
}
// 해당 사용자의 권한 정보 가져오기
Collection<? extends GrantedAuthority> authorities =
Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
// UserDetails 객체 생성해서 Authentication 리턴
UserDetails principal = userService.loadUserByUsername(claims.getSubject()); // -> 삭제
return new UsernamePasswordAuthenticationToken(
principal, // -> 삭제
accessToken, authorities);
}
/**
생략
**/
}
반응형
'Knowledge > Trouble Shooting' 카테고리의 다른 글
@AuthenticationPrincipal 에 null 값이 들어오는 에러 (0) | 2024.07.07 |
---|---|
JWT 토큰 사용 시 인증이 되지 않았다는 문제 발생 (0) | 2024.07.05 |
java.lang.StackOverflowError: null (0) | 2024.06.10 |
웹소켓 STOMP 에러 트러블 슈팅 (0) | 2024.05.27 |
Inferred type 'S' for type parameter 'S' is not within its bound; (0) | 2024.05.05 |