포스트

06.DB기반 로그인 검증

인증

  • 시큐리티를 통해 인증을 진행하는 방법은
  • 사용자가 로그인 페이지를 통해 아이디와 비밀번호를 POST로 요청
  • 스프링 시큐리티가 DB에 저장된 회원정보를 조회 후 비밀번호를 검증하고 서버 세션 저장소에 해당 아이디에 대한 세션 저장
  • UserRepository로 조회된 UserEntity를 UserDetails에 담아 시큐리티에게 전달한다
UserDetailsService
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import com.example.testsecurity.dto.CustomUserDetails;
import com.example.testsecurity.entity.UserEntity;
import com.example.testsecurity.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class CustomUserDetailsService implements UserDetailsService {

  @Autowired
  private UserRepository userRepository;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    UserEntity userData = userRepository.findByUsername(username);

    if (userData != null) {
      return new CustomUserDetails(userData);
    }

    return null;
  }
}
  • 시큐리티가 이용할 CustomUserDetailsService는 UserDetailsService 인터페이스를 구현한다.
  • findByUsername() 역시 개발자의 커스텀 메소드이다.
  • findByUsername()를 통해 사용자 정보를 불러와서 userData에 담는다.
  • userData가 null 즉, 회원이라면 CustomUserDetails에 userData를 담아 생성하며 인증이 진행이 되고, 아니라면 null을 리턴한다.
UserRepository
1
2
3
4
5
6
7
8
9
import com.example.testsecurity.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<UserEntity, Integer> {

    boolean existsByUsername(String username);

    UserEntity findByUsername(String username);
}
  • findByUsername() 커스텀 메소드
UserDetails
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import com.example.testsecurity.entity.UserEntity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;

public class CustomUserDetails implements UserDetails {

  private UserEntity userEntity;

  public CustomUserDetails(UserEntity userEntity) {
      this.userEntity = userEntity;
  }

  // 1번
  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {

    Collection<GrantedAuthority> collection = new ArrayList<>();

    collection.add(new GrantedAuthority() {

        @Override
        public String getAuthority() {

            return userEntity.getRole();
        }
    });

    return collection;
  }

  // 2번
  @Override
  public String getPassword() {
      return userEntity.getPassword();
  }

  // 3번
  @Override
  public String getUsername() {
      return userEntity.getUsername();
  }

  // 나머지 4번
  @Override
  public boolean isAccountNonExpired() {
      return true;
  }

  @Override
  public boolean isAccountNonLocked() {
      return true;
  }

  @Override
  public boolean isCredentialsNonExpired() {
      return true;
  }

  @Override
  public boolean isEnabled() {
      return true;
  }
}
  • 1번은 DB에 담긴 사용자의 인가(권한)에 관한 정보를 불러와서 처리하는 메소드
  • 2번, 3번은 비밀번호와 아이디를 반환오는 메소드
  • 4번의 경우 계정만료, 계정잠금, 비밀번호만료, 사용가능과 같은 것들을 체크하는 메소드이다
  • 디비에 만료, 잠금, 사용가능과 같은 정보들이 있다면 그것을 불러와 처리하면 된다.
  • true일 경우는 모두 사용가능한 상태이고 false로 세팅하면 사용 불가능하다.
  • 현재의 경우 DB에 관련된 컬럼들과 정보가 없기에 강제적으로 true로 세팅하였다.
참고 사이트

개발자 유미