본문 바로가기

Spring/spring security

Spring Security UserDetails, UserDetailsService 란? - 삽질중인 개발자

반응형

Spring Security - UserDetails , UserDetailsService

UserDetails 란?

Spring Security에서 사용자의 정보를 담는 인터페이스이다.

Spring Security에서 사용자의 정보를 불러오기 위해서 구현해야 하는 인터페이스로 기본 오버라이드 메서드들은 아래와 같다.

 

메소드 리턴 타입 설명 기본값
getAuthorities() Collection<? extends GrantedAuthority> 계정의 권한 목록을 리턴  
getPassword() String 계정의 비밀번호를 리턴  
getUsername() String 계정의 고유한 값을 리턴
( ex : DB PK값, 중복이 없는 이메일 값 )
 
isAccountNonExpired() boolean 계정의 만료 여부 리턴 true ( 만료 안됨 )
isAccountNonLocked() boolean 계정의 잠김 여부 리턴 true ( 잠기지 않음 )
isCredentialsNonExpired() boolean 비밀번호 만료 여부 리턴 true ( 만료 안됨 )
isEnabled() boolean 계정의 활성화 여부 리턴 true ( 활성화 됨 )

 

여기서 잘 봐야하는 메서드가 getUsername()이다.

username은 계정의 고유한 값인데 다른 블로그들을 보니까 다들 email( 로그인용 아이디 )을 넘겨준다고 하지만 email( 로그인용 아이디 )은 SSO 같은 서버를 만들게 되면 정책에 따라서 중복이 될 수도 있기에 나와 같은 경우는 보통 DB에서 User Table에 PK 값을 넘겨준다.

 

 

CustomUserDetails 구현하기

대부분의 경우 Spring Security의 기본 UserDetails로는 실무에서 필요한 정보를 모두 담을 수 없기에 아래와 같은 CustomUserDetails를 구현하여 사용한다.

@Getter
public class CustomUserDetails implements UserDetails, Serializable {

    private static final long serialVersionUID = 174726374856727L;

    private String id;	// DB에서 PK 값
    private String loginId;		// 로그인용 ID 값
    private String password;	// 비밀번호
    private String email;	//이메일
    private boolean emailVerified;	//이메일 인증 여부
    private boolean locked;	//계정 잠김 여부
    private String nickname;	//닉네임
    private Collection<GrantedAuthority> authorities;	//권한 목록
	
    
    /**
    * 해당 유저의 권한 목록
    */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
           return authorities;
    }

	/**
    * 비밀번호
    */
	@Override
    public String getPassword() {
        return password;
    }


	/**
    * PK값
    */
    @Override
    public String getUsername() {
        return id;
    }

    /**
     * 계정 만료 여부
     * true : 만료 안됨
     * false : 만료
     * @return
     */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * 계정 잠김 여부
     * true : 잠기지 않음
     * false : 잠김
     * @return
     */
    @Override
    public boolean isAccountNonLocked() {
        return locked;
    }

    /**
     * 비밀번호 만료 여부
     * true : 만료 안됨
     * false : 만료
     * @return
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }


    /**
     * 사용자 활성화 여부
     * ture : 활성화
     * false : 비활성화
     * @return
     */
    @Override
    public boolean isEnabled() {
        //이메일이 인증되어 있고 계정이 잠겨있지 않으면 true
        return (emailVerified && !locked);
    }

}

 

UserDetailsService 란?

Spring Security에서 유저의 정보를 가져오는 인터페이스이다.

Spring Security에서 유저의 정보를 불러오기 위해서 구현해야하는 인터페이스로 기본 오버라이드 메서드는 아래와 같다.

메소드 리턴 타입 설명
loadUserByUsername UserDetails 유저의 정보를 불러와서 UserDetails로 리턴

 

 

UserDetailsServiceImpl 구현하기

@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
    private final UserInfoRepository userInfoRepository;

    @Override
    public UserDetails loadUserByUsername(String loginId) throws UsernameNotFoundException {
        UserInfo userInfo = userInfoRepository.findByLoginId(loginId).orElseThrow(() -> new UsernameNotFoundException("not found loginId : " + loginId));

        CustomUserDetails customUserDetails = new CustomUserDetails();
        // 값 세팅 로직 시작
        ...
        // 값 세팅 로직 끝
        return customUserDetails;
    }
}

 

아마 대부분의 프로젝트에서 로그인 화면에서는 아래와 같은 HTML로 login용 ID와 Password를 함께 넘길 것이다.

<form action="/login" method="post">
  <input type="text" id="loginId" name="loginId" autofocus="autofocus" /> <br />
  <input type="password" id="password" name="password" /> <br />
  <input type="submit" value="Log in" />
</form>

아래에 있는 시큐리티 설정을 해준다면

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.formLogin()
                .usernameParameter("loginId")
                .passwordParameter("password")
	}
    
}

Spring Security에서 loginId를 넘겨줄 것이고 loadUserByUsername 에서 해당 값으로 DB를 조회 후 저장되어 있는 유저 정보를 가져온다.

그 후에 원하는 형태로 CustomUserDetails를 세팅해준 후 리턴해주면 Spring Security에서는 해당 유저의 정보를 조회할 때에는 CustomUserDetails에 세팅된 값으로 조회를 한 후 로직을 처리해준다.

 

 

SecurityContextHolder에서 UserDetails 불러오기 

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetails userDetails = (UserDetails)principal;

String username = userDetails.getUsername();
String password = userDetails.getPassword();

기본적으로 Spring Security의 principal 객체는 Object 형태로 UserDetails를 형변환 해야 한다.

 

 

 

 

 

반응형