울음참고 개발공부
728x90

 

 

 

Spring Security

: 인증(Authentication)과 권한(Authorization)을 처리하기 위한 강력한 프레임워크

 

 

스프링 시큐리티를 구현에 필요한 SimpleGrantedAuthority, UserDetails, UserDetailsService 에 대해 중점적으로 정리 

 

 

 

SimpleGrantedAuthority

 

- 사용자가 가진 권한(Role)을 문자열 형태로 표현하는 클래스 

public final class SimpleGrantedAuthority implements GrantedAuthority

 

- GrantedAuthority 인터페이스의 구현체

- 문자열 기반의 권한( ex: "ROLE_USER", "ROLE_ADMIN")을 저장

- 권한 체크 시 비교 기준이 됨 

- 주로 UserDetails.getAuthorities() 안에서 사용

 

 

# 권한(Role) 비교시 참고사항 

"ROLE_" prix는 관례이자 규칙!
-> hasRole("ADMIN")은 내부적으로 hasAutority("ROLE_ADMIN")로 해석

 

ex ) SecurityConfig 에서 사용 

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http
                .csrf(csrf -> csrf.disable())
                .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/mypage").hasRole("USER")
                        .requestMatchers("/admin/**").hasRole("ADMIN")
                        .anyRequest().permitAll()
                )
		// ... 생략 ... 


        return http.build();
    }

 

- Spring Security의 authorizeHttpRequests() 안에서 요청 경로별로 권한을 검사할 때 사용하는 메서드

 

- "/mypage" 경로는 ROLE_USER 권한을 가진 사용자만 접근 가능

- hasRole("USER")라고 쓰지만, **Spring Security는 내부적으로 "ROLE_" + role**로 처리함

   -> 즉, 실제로는 SimpleGrantedAuthority("ROLE_USER")가 있는지를 검사함

 

 

# 정리 

메서드  의미  내부 처리
hasRole("USER") "ROLE_USER" 권한이 있는가? hasAuthority("ROLE_USER")로 변환
hasAuthority("ROLE_USER") 정확히 "ROLE_USER" 권한이 있는가? 그대로 사용

 

 

 

UserDetails

 

- 인증된 사용 정보를 담는 객체 

- 스프링 시큐리티가 인증 후 사용자 정보를 담기 위해 사용하는 인터페이스 

- 직접 클래스를 만들고 이 인터페이스를 구현해야함

 

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    default boolean isAccountNonExpired() {
        return true;
    }

    default boolean isAccountNonLocked() {
        return true;
    }

    default boolean isCredentialsNonExpired() {
        return true;
    }

    default boolean isEnabled() {
        return true;
    }
}

 

 

 

# 메서드 설명 기본값

메서드 설명 기본값
getAuthorities() - SimpleGrantedAuthority("ROLE_USER") 같은 권한 객체들을 담은 리스트
- 로그인 후 권한 체크에 사용됨 (hasRole, hasAuthority 등)
-
getPassword() 암호화된 비밀번호( 이터베이스에 저장된 암호화된 비밀번호) -
getUsername() - 로그인 ID (보통 이메일) -
isAccountNonExpired() - 계정 만료 여부
- 만료되었으면 로그인 불가. (ex. 유효 기간 지난 계정)
- 기본값은 만료 안 됨 (true)
true
isAccountNonLocked() - 계정 잠금 여부
- 보통 로그인 실패 횟수 초과 시 잠금 처리할 때 사용
true
isCredentialsNonExpired() - 비밀번호 만료 여부
- 보안 정책상 주기적으로 비밀번호를 바꾸게 할 때 활용 가능
true
isEnabled() - 계정 활성 여부
- 관리자가 비활성 처리한 경우 false로 설정할 수 있음
true

 

 

 

# UserDetail 인터페이스를 구현한 예시

 

public class PrincipalUserDetails implements UserDetails {
	
    @Getter
    private final Member member; // 직접 만든 Member 엔티티
    
    public PrincipalUserDetails(Member member) {
    	this.member = member;
    }
    
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
    	return List.of(new SimpleGrantedAuthority(member.getRole()));
    }
    
    @Override
    public String getPassword(){
    	return member.getPassword();
    }
    
    @Ovrride
    public String getUsername(){
    	return member.getEmail();
    }
    
    // 계정 만료, 잠김 여부 등 설정
    @Ovrride
    public boolean isAccountNonExpired() { return true; }
    
    @Ovrride
    public boolean isAccountNonLocked()  { return true; }
    
    @Ovrride
    public boolean isCredentialsNonExpired() { return ture; }
    
    
    @Ovrride
    public boolean isEnabled() { return true; }
 
}

 

 

 

 

UserDetailService (인터페이스)

 

- 사용자의 이름(username, email 등)을 이용해 DB 에서 사용자 정보를 조회하고, UserDetails 객체로 반환하는 역할 

public interface UserDetailsService {
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

 

 

# UserDetails 를 반환하는 서비스 ( 실제 사용 )

@Service
public class PrincipalDetailsService implements UserDtailsService {
	private final MemberRepositorty memberRepository;
    
    public PrincipalDetailsService(MemberRepository memberRepository) {
    	this.memberRepository = memberRepository;
    }
    
    @Ovrride
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
    	MemberVO member = accountRepository.findUserByEmail(email); // email로 사용자 조회
        if (member == null) throw new UsernameNotFoundException("존재하지 않는 사용자");
        return new PrincipalUserDetails(member);
    }
}

 

- 클라이언트가 로그인 시 email/password 를 입력하고 요청하면, Spring Security 에서 내부적으로 UserDetailService.loadUserByUsername() 을 호출하여 해당 메서드에서 DB 로 부터 유저 정보를 조회해옴

 

 

 

 

# 로그인 과정 요약 

 

[사용자 로그인 요청(email, password)]
      ↓
[Spring Security 필터]
      ↓
[UserDetailsService.loadUserByUsername(email)]
      ↓
[DB에서 사용자 조회 → UserDetails 반환]
      ↓
[Spring Security가 비밀번호 일치 확인]
      ↓
[인증 성공 or 실패]

 

 

 

 

728x90
profile

울음참고 개발공부

@메각이

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!