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 은 유저와 유저네임, 패스워드도 생성자로 초기화 할수 있다.
@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 인터페이스를 구현한 클래스 중 하나로, 권한을 문자열로 표현하는 역할을 하기 때문이다.
@Override
public String getUsername() {
return this.username;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
isAccountNonExpired()은 true가 디폴트값으로 설정이 되어 있는데 유저네임과 패스워드를 사용해야되기 때문에 이렇게 수정을 함
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다."));
return new UserDetailsImpl(user, user.getUsername(), user.getPassword());
}
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
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;
}
}
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";
}
}
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);
}
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;
}
}
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 적용해보기