πŸ”’[Spring Security] LazyInitializationException + 인증 객체 ꡬ쑰 κ°œμ„ 

yeahcoldΒ·2025λ…„ 4μ›” 14일

πŸ’₯ 문제 상황 μš”μ•½

인증 μ‹œμ μ— User μ—”ν‹°ν‹° 전체λ₯Ό CustomUserDetails에 λ‹΄κ³ 
이후 μ»¨νŠΈλ‘€λŸ¬λ‚˜ μ„œλΉ„μŠ€μ—μ„œ user.getRoles()처럼 μ—°κ΄€ ν•„λ“œμ— μ ‘κ·Όν•  경우 λ‹€μŒ 였λ₯˜ λ°œμƒ:

LazyInitializationException: could not initialize proxy – no Session

🧨 κ·Όλ³Έ 원인

  • Hibernate의 μ§€μ—° λ‘œλ”©(LAZY)은 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ(session)κ°€ μ—΄λ € μžˆμ–΄μ•Ό ν”„λ‘μ‹œλ₯Ό μ΄ˆκΈ°ν™” κ°€λŠ₯
  • 인증 μ΄ν›„μ—λŠ” νŠΈλžœμž­μ…˜μ΄λ‚˜ μ„Έμ…˜ λ°–μ—μ„œ User 객체의 μ—°κ΄€ ν•„λ“œμ— μ ‘κ·Όν•˜κ²Œ 됨

πŸ•³οΈ μΆ”κ°€ 문제 - μ„Έμ…˜ 만료 μ‹œ

  • Spring Security의 Authentication κ°μ²΄λŠ” μ„Έμ…˜ 기반으둜 μœ μ§€λ¨
  • 인증 객체가 User μ—”ν‹°ν‹° 전체λ₯Ό λ“€κ³  μžˆλ‹€λ©΄, μ„Έμ…˜ 만료 이후 ν•΄λ‹Ή κ°μ²΄λŠ” λ¬΄νš¨ν™”λ¨
  • μ΄λ•Œ user.getUserRoles() λ“± 호좜 μ‹œ LAZY μ΄ˆκΈ°ν™” μ‹€νŒ¨ + μ„Έμ…˜/μΊμ‹œ 였λ₯˜ λ™μ‹œ λ°œμƒ κ°€λŠ₯

βœ… ν•΄κ²° μ „λž΅

  • 인증 객체에 μ—”ν‹°ν‹°(User)λ₯Ό 직접 λ‹΄μ§€ μ•Šκ³ , ν•„μš”ν•œ ν•„λ“œλ§Œ λ”°λ‘œ μ €μž₯ (email, id λ“±)
  • μ„œλΉ„μŠ€ κ³„μΈ΅μ—μ„œ DBλ₯Ό 톡해 λ‹€μ‹œ fetchν•˜μ—¬ μ‚¬μš© (ν•„μš”ν•  λ•Œλ§Œ, μ •ν™•ν•˜κ²Œ)

βœ… μ˜ˆμ‹œ μ½”λ“œ

CustomUserDetails κ°œμ„ 

public class CustomUserDetails implements UserDetails {
    private final String email;
    private final String nickname;

    public CustomUserDetails(String email, String nickname) {
        this.email = email;
        this.nickname = nickname;
    }

    public String getEmail() {
        return email;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return List.of(); // 별도 μ„€μ • κ°€λŠ₯
    }

    // μƒλž΅: getPassword(), isEnabled() λ“±
}

인증 μ‹œμ : μ΅œμ†Œ μ •λ³΄λ§Œ μ €μž₯

@Override
public UserDetails loadUserByUsername(String email) {
    User user = userRepository.findByEmail(email)
        .orElseThrow(() -> new UsernameNotFoundException("μœ μ € μ—†μŒ"));

    return new CustomUserDetails(user.getEmail(), user.getNickname());
}

μ‹€μ œ μ ‘κ·Ό μ‹œ: DBμ—μ„œ λ‹€μ‹œ 쑰회

@Transactional(readOnly = true)
public User getCurrentUser() {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    String email = ((CustomUserDetails) auth.getPrincipal()).getEmail();

    return userRepository.findWithRolesByEmail(email)
        .orElseThrow(() -> new IllegalStateException("μœ μ € 정보 μ—†μŒ"));
}

🧠 결둠

잘λͺ»λœ λ°©μ‹μ˜¬λ°”λ₯Έ 방식
인증 객체에 User μ—”ν‹°ν‹° 전체 보관인증 κ°μ²΄μ—λŠ” μ΅œμ†Œ μ •λ³΄λ§Œ 보관
이후 μ„œλΉ„μŠ€ κ³„μΈ΅μ—μ„œ LAZY 였λ₯˜ λ°œμƒν•„μš”ν•œ μ‹œμ μ— DBμ—μ„œ λ‹€μ‹œ fetch
μ„Έμ…˜ 만료 μ‹œ ν”„λ‘μ‹œ/μ„Έμ…˜ μ˜ˆμ™Έ λ°œμƒμΈμ¦ κ°μ²΄λŠ” μ•ˆμ „ν•˜κ²Œ μœ μ§€ κ°€λŠ₯
profile
Software Engineer

0개의 λŒ“κΈ€