안녕하세요. 좋은 강의 감사드립니다.
userDetailsService(userDetailsService) 메서드를 실제로 사용해보고 싶으신 분들에게
약간이나마 도움이 될까하여 올립니다.
코드는 정수원님의 아래 레포 코드를 참조하여 작성하였습니다.
https://github.com/onjsdnjs/corespringsecurity/blob/master/src/main/java/io/security/corespringsecurity/security/authentication/services/UserDetailsServiceImpl.java
아래의 코드 전체를 복사하여 별도의 파일에 넣거나 SecurityConfig 클래스 아래에 넣으시면 됩니다.
class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
/*
// 필요한 코드가 많아지기 때문에 ip 검사 로직은 주식처리하였습니다.
final String ip = request.getRemoteAddr();
if (loginAttemptService.isBlocked(ip)) {
throw new RuntimeException("blocked");
}
*/
UserRepository userRepository = new UserRepository();
Account account = userRepository.findByUsername(username);
if (account == null) {
if (userRepository.countByUsername(username) == 0) {
throw new UsernameNotFoundException("No user found with username: " + username);
}
}
Set<String> userRoles = account.userRole
.stream()
.map(Account.UserRole::getRoleName)
.collect(Collectors.toSet());
return new UserDetail(account, new ArrayList<>(userRoles));
}
}
class UserDetail extends org.springframework.security.core.userdetails.User {
public UserDetail(Account account, List<String> roles) {
super(account.username, account.password, roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
}
}
// 코드를 줄이기 위해 getter를 의도적으로 사용하지 않고 모든 변수를 public으로 만들었습니다.
class Account {
public final String username;
public final String password;
public final List<UserRole> userRole = new ArrayList<>();
public Account(String username, String password, UserRole userRole) {
this.username = username;
this.password = password;
this.userRole.add(userRole);
}
enum UserRole {
USER("유저"), MANAGER("관리자");
private final String roleName;
UserRole(String roleName) {
this.roleName = roleName;
}
public String getRoleName() {
return roleName;
}
}
}
// 데이터베이스 연결 없이도 동작할 수 있도록 하드코딩된 결과로 설정하였습니다.
class UserRepository {
public Account findByUsername(String username) {
return new Account("charlie", "1234", Account.UserRole.USER);
}
public int countByUsername(String username) {
return 1;
}
}
복붙하셨다면 아래와 같이 사용하실 수 있습니다.
@Override
protected void configure(HttpSecurity http) throws Exception {
//http.formLogin()......
// 스프링을 사용해서 빈으로 등록하는 것이 맞지만 단순히 결과를 보는 것에만 집중하였습니다.
UserDetailsService userDetailsService = new UserDetailsService();
http.rememberMe()
.rememberMeParameter("remember")
.tokenValiditySeconds(3600)
.userDetailsService(userDetailsService);
}
강의를 더 보면 알 수 있을지도 모르겠으나
.userDetailsService(매개변수)
여기서 매개변수 값은 org.springframework.security.core.userdetails.UserDetailsService의 loadUserByUsername(String username) 을 구현한 클래스여야 하며 해당 구현 메서드를 기반으로 동작하는 것 같아 보입니다.
또한 loaduserByUsername이 반환하는 UserDetail은 org.springframework.security.core.userdetails.User 를 상속받고, "실제 유저정보"를 UserDetail 안에서 상위 객체인 User 생성자에 값을 초기화해 설정할 수 있는 것으로 보입니다.
답글