본문 바로가기
Computer Science/Spring Security

Spring Security 사용자 관리

by 콩순이냉장고 2023. 6. 25.

 

 

사용자 관리를 위해서 UserDetailsServcice와 UserDetailsManage 인터페이스를 이용한다.

 

 

UserDetailsService 란?

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

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

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

UserDetailserService 의 loadUserByUsername(String username) 메서드를 호출해 주어진 사용자 이름을 가진 사용자의 세부정보를 얻습니다.

사용자 이름이 존재하지 않으면 메서드가 UsernameNotFoundException을 투척합니다.

 

 

 

 

UserDetailsManager 란 ? 

Spring Security에서 유 사용자 추가, 수정, 삭제 작업을 하기위한 인터페이스입니다.

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

메소드 리턴 타입 설명
changePassword(String oldPassword, String newPassword)
 
void 유저의 패스워드 변경
createUser(UserDetails user) void 새로운 유저 생성
deleteUser(String username) void 시스템에서 유저를 삭제
updateUser(UserDetails user) void 해당 유저 업데이트
userExists(String username) boolean 해당유저가 존재하는지 확인

 

 

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 값을 넘겨준다.

 

 

.

개발자는 스프링 시큐리티에 있는 UserDetails 계약을 구현해서 프레임워크가 이해할 수 있게 사용자를 기술해야한다.

 

 

 

 

UserDeatils 계약을 확인하면 사용자는 4가지 같은 작업을 할수있습니다.

  • 계정만료 
  • 계정잠금
  • 자격 증명 만료
  • 계정 비활성화

isAccountNonExpired(), isAccountNonLocked(). isCredentialsNonExpired() isEnabled() 메서드를 재정의해서 true를 반환하게 해야하지만, 특정조건에 계정이 만료되거나 잠기는 것은 아니다.

기능을 구현할 필요하 없다면 단순하게 네 메서드가 true를 반환하게 하면 된다.

 

 

 

GrantedAuthority 란?

GrantedAuthority 인터페이스는 사용자 세부 정보의 정의에 이용되며 사용자에게 허가된 이용 권리를 나타낸다.

사용자는 권한이 하나도 없거나 여러 권한을 가질수 있지만 일반적으로 하나 이상의 권한을 가진다.

 

메소드 리턴 타입 설명
getAuthority() String 인증받은 사용자의 authorities를 조회할 수 있다

 

 

 

UserDetails 형식의 인스턴스 만드는 방법

        UserDetails u = User.withUsername("bill") //withUsername메서드는 UserBuilder를 반환
                .password("12345")
                .authorities("read","wrtie")
                .accountExpired(false)
                .disabled(true)
                .build();

 

User.UserBuilder 인스턴스 만들기

   User.UserBuilder builder1 = User.withUsername("bill"); //주어진 사용자 이름으로 사용자생성
        UserDetails u1 = builder1
                .password("12345")
                .authorities("read","write")
                .passwordEncoder(p->encode(p)) //인코딩을 수행하는 함수
                .accountExpired(false)
                .disabled(true)
                .build();
        
        User.UserBuilder builder2 = User.withUserDetails(u1);
        UserDetails u2 = builder2.build();

 

 

UserDetailsService의 구현

 

public class User implements UserDetails {

    private final String username;
    private final String password;
    private final String authority;

    public User(String username, String password, String authority) {
        this.username = username;
        this.password = password;
        this.authority = authority;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return List.of(() -> authority);
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

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

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

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

    @Override
    public boolean isEnabled() {
        return true;
    }
}
public class InMemoryUserDetailsService implements UserDetailsService {

    private final List<UserDetails> users;

    public InMemoryUserDetailsService(List<UserDetails> users) {
        this.users = users;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return users.stream()
                .filter(u -> u.getUsername().equals(username)) //사용자의 목록에서 요청된 사용자 이름과 일치하는 항목을 필터링
                .findFirst()//일치하는 사용자가 있다면 반환
                .orElseThrow(() -> new UsernameNotFoundException("User not found")); //그외 예외투척
    }
}

 

 

사용자 관리 JDBCUserDetailsManager를 이용

 

JDBCUserDetailsManager는 SQL 데이터베이스에 저장된 사용자를 관리하며 JDBC를 통해 데이터베이스에 직접 연결한다.

 

이를 위해서는 resources 폴더에 schema.sql및 data.sql의 두파일을 추가하면 됨

schema 파일에는 테이블 만들기 , 수정, 삭제 같은 데이터베이스의 구조에 관한 커리를 추가하고

 

data.sql 파일에는 insert,update, delete 같은 테이블 안의 데이터를 처리하는 쿼리를 추가

 

schema.sql

CREATE TABLE IF NOT EXISTS `spring`.`users` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(45) NULL,
  `password` VARCHAR(45) NULL,
  `enabled` INT NOT NULL,
  PRIMARY KEY (`id`));

CREATE TABLE IF NOT EXISTS `spring`.`authorities` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(45) NULL,
  `authority` VARCHAR(45) NULL,
  PRIMARY KEY (`id`));


data.sql

INSERT INTO `spring`.`authorities` VALUES (NULL, 'john', 'write');
INSERT INTO `spring`.`users` VALUES (NULL, 'john', '12345', '1');

 

 

출처: https://programmer93.tistory.com/68

 

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

Spring Security - UserDetails , UserDetailsService UserDetails 란? Spring Security에서 사용자의 정보를 담는 인터페이스이다. Spring Security에서 사용자의 정보를 불러오기 위해서 구현해야 하는 인터페이스로 기본

programmer93.tistory.com

 

'Computer Science > Spring Security' 카테고리의 다른 글

암호처리  (0) 2023.07.02