처음에는 그냥
redis-server.exe를 누르고redis-cli.exe를 눌렀는데 뭔가 안 됨. 그래서 Bash창을 켜서redis-server.exe명령어를 통해 오류 로그를 확인하고 해결함.
여기처럼 Redis 비밀번호를 설정했는데
(error) ERR Client sent AUTH, but no password is set이런 오류가 뜸. 해결 못함. 결국 Redis에 비밀번호 등록이 잘 안된 것으로 판단, Spring Boot에서도 Redis에
setPassword부분을 주석처리함.
다음 날 노트북을 다시 켜니까
redis-cli.exe에서auth redispw이런 느낌으로 접속가능함.. 근데 그러고 웃긴 건 Spring Boot 프로젝트에서 Redis에setPassword를 안해도 접속가능하고 해도 접속가능함.. 뭐지?
@RequiredArgsConstructor를 사용했을 때 빈을 못찾음아래처럼 롬복 애노테이션을 사용하려고 했는데
@Service @RequiredArgsConstructor @Slf4j public class UserService { private RedisRepository redisRepository; //(중략)아래와 같은 오류 발생
java.lang.NullPointerException: Cannot invoke "com.example.securitytest.RedisRepository.getRefreshToken(String)" because "this.redisRepository" is null
알고보니 @RequiredArgsConstructor 은 final이 붙은 필드로만 생성자 주입을 해준다고 함. 아래처럼 final을 붙여서 해결.
@Service
@RequiredArgsConstructor
@Slf4j
public class UserService {
private final RedisRepository redisRepository;
//(중략)
/logout을 못찾음정말정말 황당했던 오류였다. Controller에서 url을
/logout으로 설정했는데 포스트맨으로 쏴볼때는 자꾸/login으로 연결되어 오류가 발생하는 것이었다."timestamp": "2024-03-04T14:48:36.592+00:00", "status": 405, "error": "Method Not Allowed", "trace": "org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' is not supported\r\n\tat ...(중략)... "message": "Method 'GET' is not supported.", "path": "/login"그냥
/asdf이런 식으로 했을 때는 잘 되는데/logout만 그랬다. 예전에도 처음 Spring Security를 설정했을 때 기본으로/login으로 이동되어 이 설정을 끈 적이 있었기 때문에, 이것도 혹시나 그런 현상이 아닐까 추측하고 디버그 레벨을DEBUG로 낮춰서 요청 url을 확인했다. 아니나다를까/logout으로 요청하면/login?logout이런 식으로 리다이렉트가 되고 있었다. 그냥 웹페이지에서 실행해도/login?logout로 연결되며whilelabel오류가 났다.
구글링을 통해 해결법을 찾기는 했다.
WebSecurityConfig.java의filterChain메소드에 아래 내용을 추가하고,http .logout(logout -> logout .logoutUrl("/logout") .logoutSuccessHandler(customLogoutSuccessHandler) );
CustomLogoutSuccessHandler를 따로 정의하는 것이다.@Slf4j class CustomLogoutSuccessHandler implements LogoutSuccessHandler { @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { // 로그아웃 성공 시 원하는 동작을 여기에 구현하세요. log.info("logout 여기"); response.setStatus(HttpServletResponse.SC_OK); } }그런데 결국 이렇게 해도 컨트롤러에
/logout메소드로 이동되게는 못하는 것 같았다. 따라서 이 부분은 이정도로만 넘어가고 컨트롤러에서는/logout대신/userlogout을 사용하는 것으로 스스로 타협봤다..
getAuthorities()이번에는 Spring Security의
getAuthorities()메소드에 대해서 좀 더 알게 되었다. 마지막에 DB를 추가하게 되면서, 매번signup을 시키는게 귀찮아서 그냥 DB에 추가를 했더니,Role이 없어서SecurityContextHolder.getContext().setAuthentication(authentication);이 부분이 제대로 시행되지 않았다. 즉 여기서 정상적으로authentication이 담겨야@AuthenticationPrincipal등을 사용할 수 있다. 이후 아래처럼 코드를 수정하고signup메소드를 통해 정상적으로 프로세스를 진행할 수 있었다.
@Service
@RequiredArgsConstructor
@Slf4j
public class CustomUserDetailService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//DB 사용하지 않았을 때 임시방편
// log.info("loadUserByUsername : {}",username);
// HashSet hs = new HashSet<Role>();
// hs.add(Role.USER);
// return new User(1L, username, "", hs);
return userRepository.findByEmail(username)
.orElseThrow(() -> new RuntimeException("아이디나 비밀번호가 일치하지 않습니다."));
}
}
roles에서의 오류위에서 살펴보았다 시피
User클래스에는roles을 설정해줘야 한다. 그런데 해당 필드 관련해서 아래와 같은 오류가 났다.org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.securitytest.User.roles: could not initialize proxy - no Session at (중략)JPA의 영속성 관련한 오류같다.
roles가 다른 테이블로 있으면서 유저 테이블과 해당 테이블이 연관관계가 되어,roles를 읽기 전에 유저 테이블을 읽는게 끝나버린 오류 같다.. 자세한건 아직 JPA를 잘 모르니 패스..
어쨋든 해결방법은 두 가지가 있는 것 같다. 호출되는 메소드에
@Transactional을 부티던지, 해당 필드에@ElementCollection(fetch = FetchType.EAGER)를 쓰는 것이다.@Transactional이 권장되는 방법 같던데@Transactional썼더니 안 돼서User클래스의private Set<Role> roles = new HashSet<>();에@ElementCollection(fetch = FetchType.EAGER)를 붙였다..
처음에
JpaRepository를 상속받는RefreshTokenRepository를 생성했는데, 내가 알기로는 따로 메소드를 재정의하지 않아도.save()같은 메소드를 사용할 수 있는데, 처음에는 다른 곳에서 의존성 주입 후.save()등 메소드들이 호출이 안 됐었다.. 그런데 내가 기존에 재정의한Optional<RefreshToken> findByEmail(String email);를 주석처리했더니 정상호출됐다. 근데 그러고 다시 주석을 풀어도 정상호출이 됐다.. 무슨 오류인지, 왜 해결이 됐는지 모르겠다....