[Spring] Spring Security(4) UserDetails, UserDetailsService Custom 해보기

hyewon jeong·2023년 1월 4일
0

Spring

목록 보기
13/59

🍃 4. UserDetails, UserDetailsService Custom 해보기

  • User.java**
  • UserRoleEnum.java**
  • UserRepository.java**
  • UserDetailsImpl.java**
  • UserDetailsServiceImpl.java**

UserDetailsImpl

인증이 완료된 사용자 추가

		private final User user; // 인증완료된 User 객체
    private final String username; // 인증완료된 User의 ID
    private final String password; // 인증완료된 User의 PWD

    public UserDetailsImpl(User user, String username, String password) {
        this.user = user;
        this.username = username;
        this.password = password;
    }
		
	//  인증완료된 User 를 가져오는 Getter
    public User getUser() {
        return user;
    }

UserDetailsImpl 은 유저와 유저네임, 패스워드도 생성자로 초기화 할수 있다.

사용자의 권한 GrantedAuthority 로 추상화 및 반환

		@Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        UserRoleEnum role = user.getRole();
        String authority = role.getAuthority();

        SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(simpleGrantedAuthority);

        return authorities;
    }

유저의 권한을 가지고 와서 이것을 스트링값인 authority 로 만든 다음에
new SimpleGrantedAuthority로 추상화해서 사용한다 .

🙄 ?? 왜 그냥 유저 권한을 사용하지 않고 스트링 값인 authority로 만들어 추상화 하는 걸까???
->
유저의 권한을 UserRoleEnum로 정의한 뒤, SimpleGrantedAuthority로 추상화하는 이유는 주로 Spring Security와 같은 보안 프레임워크에서 사용자의 권한을 처리하고 관리하기 위함인데 ,
Spring Security에서는 사용자의 권한을 GrantedAuthority 인터페이스를 구현한 객체로 표현한다. 그리고 SimpleGrantedAuthority는 GrantedAuthority 인터페이스를 구현한 클래스 중 하나로, 권한을 문자열로 표현하는 역할을 하기 때문이다.

사용자의 ID, PWD Getter

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

    @Override
    public String getPassword() {
        return this.password;
    }
    
    @Override
public boolean isAccountNonExpired() {
    return false;
}

isAccountNonExpired()은 true가 디폴트값으로 설정이 되어 있는데 유저네임과 패스워드를 사용해야되기 때문에 이렇게 수정을 함

UserDetailsServiceImpl

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

        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다."));

        return new UserDetailsImpl(user, user.getUsername(), user.getPassword());
    }

UserDetailsImpl 인증객체 생성에 사용

UserDetails userDetails = userDetailsService.loadUserByUsername(username);
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
  • user.class
package com.sparta.springsecurity.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Getter
@NoArgsConstructor
@Entity(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    private String username;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false)
    @Enumerated(value = EnumType.STRING)
    private UserRoleEnum role;

    public User(String username, String password, UserRoleEnum role) {
        this.username = username;
        this.password = password;
        this.role = role;
    }
}
  • UserRoleEnum.java
package com.sparta.springsecurity.entity;

public enum UserRoleEnum {
    USER(Authority.USER),  // 사용자 권한
    ADMIN(Authority.ADMIN);  // 관리자 권한

    private final String authority;

    UserRoleEnum(String authority) {
        this.authority = authority;
    }

    public String getAuthority() {
        return this.authority;
    }

    public static class Authority {
        public static final String USER = "ROLE_USER";
        public static final String ADMIN = "ROLE_ADMIN";
    }
}
  • UserRepository.java
package com.sparta.springsecurity.repository;


import com.sparta.springsecurity.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);

}
  • UserDetailsImpl.java
package com.sparta.springsecurity.security;


import com.sparta.springsecurity.entity.User;
import com.sparta.springsecurity.entity.UserRoleEnum;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

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

public class UserDetailsImpl implements UserDetails {

    private final User user;
    private final String username;
    private final String password;

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

    public User getUser() {
        return user;
    }

    @Override  
    public Collection<? extends GrantedAuthority> getAuthorities() {
        UserRoleEnum role = user.getRole();
        String authority = role.getAuthority();

        SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(simpleGrantedAuthority);

        return authorities;
    }

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

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

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

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

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

    @Override
    public boolean isEnabled() {
        return false;
    }
}
  • UserDetailsServiceImpl.java
package com.sparta.springsecurity.security;

import com.sparta.springsecurity.entity.User;
import com.sparta.springsecurity.repository.UserRepository;
import lombok.RequiredArgsConstructor;
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
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {

    private final UserRepository userRepository;

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

        System.out.println("UserDetailsServiceImpl.loadUserByUsername : " + username);

        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다."));

        return new UserDetailsImpl(user, user.getUsername(), user.getPassword());
    }

}

UserDetailImpl은 그렇게 가지고 온 유저의 정보를 활용해서 만든 객체인데 이거를 HttpRequest에서 user가 입력한 username과 패스워드를 가지고 오고 활용을하는 Filter가 필요하다

그래서 이 UserDetailsImpl과 UserDetailsServiceImpl을 사용하는 필터를 만들어서 추가할 예정이다.
[Spring] Spring Security (6)CustomSecurityFilter 적용해보기

profile
개발자꿈나무

0개의 댓글