주의
이 책은 Spring Security 5 버전을 기준으로 작성되었으므로, Spring Boot 3.X 버전에서는 일부 클래스가 더 이상 사용되지(deprecated) 않을 수 있습니다.
1. 스프링 시큐리티의 인증 구현
- 빨간색 테두리가 있는 두 상자는 기본적으로 두 구성 요소 UserDetailsService와 PasswordEncoder
- 두 구성 요소는 종종 `사용자 관리 부분`이라고 말하는 흐름의 일부분을 처리
- 이 단원에서 UserDetailsService 및 PasswordEncoder는 사용자 세부 정보와 자격 증명을 직접 처리하는 구성 요소

- 사용자 관리를 위해서는 UserDetailsService 및 UserDetailsManager 인터페이스를 이용
- UserDetailsService는 사용자 이름으로 사용자를 검색하는 역할하며 해당 작업은 프레임워크가 인증을 완료하는 데 반드시 필요한 유일한 작업
- UserDetailsManager는 대부분의 애플리케이션에 필요한 사용자 추가, 수정 및 삭제 작업을 추가함
- SOLID 원칙의 인터페이스 분리 원칙의 훌륭한 예시, 인터페이스를 분리하면 앱에 필요 없는 동작을 구현하도록 프레임워크에서 강제하지 않기 때문에 유연성이 향상됨
- 사용자를 인증하는 기능만 필요한 경우 UserDetailsService 계약만 구현하면 필요한 기능을 제공할 수 있음
- 사용자를 관리하려면 UserDetailsService 및 UserDetailsManager 구성 요소에 사용자를 나타내는 방법이 필요
- 스프링 시큐리티에서 사용자는 사용자가 수행할 수 있는 작업을 나타내는 이용 권리의 집합을 가짐
- 사용자가 수행할 수 있는 작업을 GrantedAuthority 인터페이스로 나타내며 이를 종종 권한이라고 지칭하며 하나 이상의 권한을 가짐

2. 사용자 기술하기
- 스프링 시큐리티에서 사용자 정의는 UserDetails 계약을 준수해야 함
- UserDetails 계약은 스프링 시큐리티가 이해하는 방식으로 사용자를 나타냄
- 애플리케이션에서 사용자를 기술하는 클래스는 프레임워크가 이해할 수 있도록 해당 인터페이스를 구현해야 함
UserDetails 계약의 정의 이해하기
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface UserDetails extends Serializable { | |
// 앱 사용자가 수행할 수 있는 작업을 GrantedAuthority 인스턴스의 컬렉션으로 반환 | |
Collection<? extends GrantedAuthority> getAuthorities(); | |
// 사용자 자격 증명을 반환하는 메서드 | |
String getPassword(); | |
String getUsername(); | |
// 사용자 자격 증명을 반환하는 메서드 | |
// 사용자 계정을 필요에 따라 활성화 또는 비활성화하는 네 메서드 | |
boolean isAccountNonExpired(); | |
boolean isAccountNonLocked(); | |
boolean isCredentialsNonExpired(); | |
boolean isEnabled(); | |
// 사용자 계정을 필요에 따라 활성화 또는 비활성화하는 네 메서드 | |
} |
- getUsername() 및 getPassword() 메서드는 각각 사용자 이름과 암호를 반환하며 반환된 사용자 이름과 암호는 앱에서 인증 과정에 사용되고 계약에서 인증과 관련된 유일한 세부 정보
- 나머지 다섯 메서드는 모두 사용자가 애플리케이션의 리소스에 접근할 수 있도록 권한을 부여하기 위한 것
- 일반적으로 앱은 사용자가 애플리케이션에서 의미 있는 작업을 수행하도록 허용해야 함
- i.g. 사용자는 데이터를 읽고, 쓰고, 삭제할 수 있어야 함
- 사용자에게 작업을 수행할 이용 권리가 있거나 없다고 말하며 사용자가 가진 이용 권리를 나타내는 것이 권한이며 getAuthorities() 메서드는 사용자에게 부여된 권한의 그룹을 반환하도록 구현
- UserDetails 계약을 보면 사용자는 다음과 같은 작업을 할 수 있음
- 계정 만료
- 계정 잠금
- 자격 증명 만료
- 계정 비활성화
- 애플리케이션의 논리에서 이러한 사용자 제한을 구현하려면 isAccountNonExpired(), isAccountNonLocked(), isCredentialNonExpired(), 그리고 isEnabled() 메서드를 재정의해서 true를 반환하게 해야 함
- 모든 애플리케이션에서 특정 조건에 계정이 만료되거나 잠기는 것이 아니므로 애플리케이션에서 이러한 기능 구현이 필요 없을 경우 단순하게 네 메서드가 true를 반환하게 하면 됨
GrantedAuthority 계약 살펴보기
- 앞서 설명했다시피 사용자에게 허가된 작업을 권한이라고 지칭
- 권한은 사용자가 애플리케이션에서 수행할 수 있는 작업을 나타냄
- i.g. 어떤 애플리케이션에서 일부 사용자는 특정 정보를 읽을 수만 있지만 다른 사용자는 데이터를 변경할 수도 있음
- 애플리케이션은 사용자가 필요로 하는 권한이 애플리케이션의 기능 요구 사항에 따라 다른 유형의 사용자를 구분해야 하며 스프링 시큐리티에서는 GrantedAuthority 인터페이스로 권한을 나타냄
- GrantedAuthority 인터페이스는 사용자 세부 정보의 정의에 이용되며 사ㅏ용자에게 허가된 이용 권리를 나타냄
- 사용자는 권한이 하나도 없거나 여러 권한을 가질 수 있지만, 일반적으로 하나 이상의 권한을 가짐
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface GrantedAuthority extends Serializable { | |
String getAuthority(); | |
} |
- 권한을 생성하려면 나중에 권한 부여 규칙을 작성할 때 참조할 수 있게 해당 이용 권리의 이름만 찾으면 됨
- i.g. 사용자는 애플리케이션이 관리하는 레코드를 읽거나 삭제할 수 있으며 이러한 작업에 부여한 이름을 바탕으로 권한 부여 규칙을 작성함
- SimpleGrantedAuthrotiy 클래스로 GrantedAuthority 형식의 변경이 불가능한 인스턴스를 생성할 수 있음
- 인스턴스를 만들 때는 권한 이름을 지정해야 함
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
GrantedAuthority g1 = () -> "READ"; | |
GrantedAuthority g2 = new SimpleGrantedAuthority("READ"); |
최소한의 UserDetails 구현 작성
- 아래 코드는 DummyUser라는 클래스로 최소한의 사용자 기술을 구현하는 예제
- 해당 클래스로 UserDetails 계약의 메서드를 구현하는 방법을 볼 수 있음
- 해당 클래스의 인스턴스는 사용자명이 "bill"이고 암호는 "12345"이며 "READ" 권한이 있는 한 사용자를 나타냄
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class DummyUser implements UserDetails { | |
@Override | |
public String getUsername() { | |
return "bill"; | |
} | |
@Override | |
public String getPassword() { | |
return "12345"; | |
} | |
@Override | |
public Collection<? extends GrantedAuthority> getAuthorities() { | |
return List.of(() -> "READ"); | |
} | |
@Override | |
public boolean isAccountNonExpired() { | |
return true; | |
} | |
@Override | |
public boolean isAccountNonLocked() { | |
return true; | |
} | |
@Override | |
public boolean isCredentialsNonExpired() { | |
return true; | |
} | |
@Override | |
public boolean isEnabled() { | |
return true; | |
} | |
} |
- 실제 애플리케이션에서는 다른 사용자를 나타내는 인스턴스를 생성할 수 있도록 클래스를 작성해야 함
- 이 경우 아래 코드 예제와 같이 클래스가 사용자 이름과 암호를 특성으로 포함하도록 정의해야 함
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SimpleUser implements UserDetails { | |
private final String username; | |
private final String password; | |
private final String authority; | |
public SimpleUser(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; | |
} | |
} |
빌더를 이용해 UserDetailss 형식의 인스턴스 만들기
- 애플리케이션에서 클래스를 하나 이상 선언해도 되지만, User 빌더 클래스로 사용자를 나타내는 인스턴스를 간편하게 얻을 수 있음
- org.springframework.security.core.userdetails 패키지의 User 클래스는 UserDetails 형식의 인스턴스를 간단하게 만드는 방법이며 해당 클래스로 UserDetails의 변경이 불가능한 인스턴스를 만들 수 있음
- 최소한 사용자명과 암호가 필요하고 사용자 이름은 빈 문자열이 아니어야 함
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
UserDetails u = User.withUsername("bill") | |
.password("12345") | |
.authorities("read", "write") | |
.accountExpired(false) | |
.disabled(true) | |
.build(); |
- User.withUsername(String username) 메서드는 User 클래스에 중첩된 빌더 클래스 UserBuilder의 인스턴스를 반환함
- 빌더를 만드는 다른 방법은 UserDetails의 다른 인스턴스에서 시작하는 것
- 아래 예제의 첫 번째 행은 사용자 이름을 뭄ㄴ자열로 지정하는 것으로 시작해서 UserBuilder를 만듦
- 아래 예제에 나온 모든 빌더를 이용해 UserDetailss 계약으로 표현되는 사용자를 얻을 수 있음
- 빌더 파이프라인의 끝에서 build() 메서드를 호출하며, 별도로 암호 인코딩 함수를 지정한 경우 이를 적용해서 암호를 인코딩한 뒤 UserDetails의 인스턴스를 구성한 후 반환함
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
User.UserBuilder builder1 = User.withUsername("bill"); // 주어진 사용자 이름으로 사용자 생성 | |
UserDetails u1 = builder1 | |
.password("12345") | |
.authorities("read", "write") | |
.passwordEncoder(p -> encode(p)) | |
.accountExpired(false) | |
.disabled(true) | |
.build(); | |
// 기존의 UserDetails 인스턴스에서 사용자를 만들 수도 있음 | |
User.UserBuilder builder2 = User.withUserDetails(u); | |
UserDetails u2 = builder2.build(); |
사용자와 연관된 여러 책임 결합
- 실제 시나리오는 기존에 설명한 예제보다 더 복잡할 때가 많고 한 사용자가 여러 책임을 갖는 것이 일반적
- 사용자를 데이터베이스에 저장할 경우 애플리케이션에 지속성 엔티티를 나타내는 클래스가 필요
- 또는 다른 시스템에서 웹 서비스를 통해 사용자를 가져오면 사용자 인스턴스를 나타내는 데이터 전송 객체가 필요
- 간단하고 일반적인 첫 번째 사례로 SQL 데이터베이스 테이블에 사용자를 저장한다고 가정하고 예제를 간단하게 만들기 위해 사용자마다 하나의 권한 부여했음
- 이 클래스에는 JPA 어노테이션, getter, setter가 포함되어 있고, 그중 getUsername() 및 getPassword()는 모두 UserDetails 계약의 메서드를 재정의함
- getAuthority() 메서드는 String을 반환하고 getAuthorities() 메서드는 Collection을 반환하며 getAuthority() 메서드는 클래스의 단순한 getter이고 getAuthorities()는 UserDetails 인터페이스의 메서드를 구현함
- 단순한 예제 코드이므로 이렇게 작성했지만 다른 엔티티에 대한 관계를 추가할 경우 복잡도가 올라가는 바람직하지 않은 코드
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Entity | |
public class User implements UserDetails { | |
@Id | |
private int id; | |
private String username; | |
private String password; | |
private String authority; | |
@Override | |
public String getUsername() { | |
return this.username; | |
} | |
@Override | |
public String getPassword() { | |
return this.password; | |
} | |
public String getAuthority() { | |
return this.authority; | |
} | |
@Override | |
public Collection<? extends GrantedAuthority> getAuthorities() { | |
return List.of(() -> this.authority); | |
} | |
// 중략 | |
} |
- 코드가 복잡한 이유는 두 책을 혼합했기 때문
- 애플리케이션에 두 책임이 필요한 것은 맞지만, 모두 한 클래스에 넣을 필요는 없음
- User 클래스를 장식하는 SecurityUser라는 별도의 클래스를 정의함에 따라 책임을 분리할 수 있음
- SecurityUser 클래스는 UserDetails 계약을 구현하고 이를 이용해 사용자를 스프링 시큐리티 아키텍처에 연결하고 User 클래스에는 JPA 엔티티 책임만 남아 있음
- SecurityUser 클래스로 User 엔티티 클래스를 장식하고 스프링 시큐리티 계약에 필요한 코드를 추가해서 JPA 엔티티에 코드를 섞어 결과적으로 여러 다른 작업을 구현하지 않도록 했음
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Data | |
@Entity | |
public class User { | |
@Id | |
private int id; | |
private String username; | |
private String password; | |
private String authority; | |
} | |
public class SecurityUser implements UserDetails { | |
private final User user; | |
public SecurityUser(User user) { | |
this.user = user; | |
} | |
@Override | |
public String getUsername() { | |
return user.getUsername(); | |
} | |
@Override | |
public String getPassword() { | |
return user.getPassword(); | |
} | |
@Override | |
public Collection<? extends GrantedAuthority> getAuthorities() { | |
return List.of(() -> user.getAuthority()); | |
} | |
// 중략 | |
} |
3. 스프링 시큐리티가 사용자를 관리하는 방법 지정
UserDetailsService 계약의 이해
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface UserDetailsService { | |
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException; | |
} |
- 사용자 이름이 고유하다고 가정했을 때 인증 구현은 loadUserByUsername(String username) 메서드를 호출해 주어진 사용자 이름을 가진 사용자의 세부 정보를 얻음
- 해당 메서드가 반환하는 사용자는 UserDetails 계약의 구현
- 사용자 이름이 존재하지 않으면 메서드가 UsernameNotFoundException을 투척

UserDetailsService 계약 구현
- 시스템이 어떻게 작동하는지와 관계없이 스프링 시큐리티에 필요한 것은 사용자 이름으로 사용자를 검색하는 구현을 제공하는 것
- 아래 예제에서는 사용자의 메모리 내 목록을 이용하는 UserDetailsService를 작성하며 InMemoryUserDetailsManager 구현을 이용
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// User 클래스는 불변 | |
// 인스턴스를 만들 때 세 특성의 값을 지정하며 이러한 값은 나중에 변경 불가 | |
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; | |
} | |
// 인스턴스를 만들 때 지정한 이름의 GrantedAuthority 객체만 포함하는 목록 반환 | |
@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 { | |
// 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")); // | |
} | |
} |
- loadUserByUsername(String username) 메서드는 주어진 사용자 이름으로 사용자의 목록을 검색하고 원하는 UserDetails 인스턴스를 반환하고 주어진 사용자 이름이 발견되지 않으면 UsernameNotFoundException 예외가 발생함
- 이제 이 구현을 UserDetailssService로 이용할 수 있으며 아래 예제 코드에는 이를 구성 클래스에 빈으로 추가한 뒤 한 사용자를 등록하는 방법을 소개
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Configuration | |
public class ProjectConfig { | |
@Bean | |
public UserDetailsService userDetailsService() { | |
UserDetails u = new User("john", "12345", "read"); | |
List<UserDetails> users = List.of(u); | |
return new InMemoryUserDetailsService(users); | |
} | |
@Bean | |
public PasswordEncoder passwordEncoder() { | |
return NoOpPasswordEncoder.getInstance(); | |
} | |
} |
UserDetailsManager 계약 구현
- UserDetailsManager 인터페이스는 UserDetailsService 계약을 확장하고 메서드를 추가함
- 스프링 시큐리티가 인증을 수행하려면 UserDetailsService 계약이 필요한데, 일반적으로 애플리케이션에는 사용자를 관리하는 기능이 필요하고 대부분의 앱은 최소한 새 사용자를 추가하거나 기존 사용자를 삭제할 수 있어야 함
- 이때는 스프링 시큐리티에 정의된 더 구체적인 인터페이스인 UserDetailsManager를 구현하는데, UserDetailsManager는 UserDetailsService를 확장하고 개발자가 구현할 작업을 좀 더 포함하고 있음
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface UserDetailsManager extends UserDetailsService { | |
void createUser(UserDetails var1); | |
void updateUser(UserDetails var1); | |
void deleteUser(String var1); | |
void changePassword(String var1, String var2); | |
boolean userExists(String var1); | |
} |
사용자 관리에 JdbcUserDetailsManager 이용
- InMemoryUserDetailsManager 외에 다른 UserDetailManager인 JdbcUserDetailsManager도 자주 이용함
- JdbcUserDetailsManager는 SQL 데이터베이스에 저장된 사용자를 관리하며 JDBC를 통해 데이터베이스에 직접 연결함
- 이처럼 JdbcUserDetailsManager는 데이터베이스 연결과 관련한 다른 프레임워크나 사양으로부터 독립적일 수 있음
- 아래 예제는 데이터베이스 한 개와 테이블을 두 개 생성하고 JdbcUserDetailsManager 이용 방법을 보여주는 데모 애플리케이션
- 해당 에제에서 데이터베이스 이름은 spring으로 지정하고 테이블 이름은 각각 users 및 authorities로 지정 (이러한 이름은 JdbcUserDetailsManager가 인식하는 기본 테이블명)
- users 테이블의 목적은 사용자 레코드를 저장하는 것이며 JdbcUserDetailsManager 구현은 users 테이블에 사용자 이름, 암호, 그리고 사용자 활성화 여부를 저장하는 세 컬럼이 있다고 가정
- 편의를 위해 라이브러리 종속성 추가는 생략

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE TABLE IF NOT EXISTS `spring`.`users` ( | |
`id` INT NOT NULL AUTO_INCREMENT, | |
`username` VARCHAR(45) NOT NULL, | |
`password` VARCHAR(45) NOT NULL, | |
`enabled` INT NOT NULL, | |
PRIMARY KEY (`id`)); | |
CREATE TABLE IF NOT EXISTS `spring`.`authorities` ( | |
`id` INT NOT NULL AUTO_INCREMENT, | |
`username` VARCHAR(45) NOT NULL, | |
`authority` VARCHAR(45) NOT NULL, | |
PRIMARY KEY (`id`)); | |
INSERT IGNORE INTO `spring`.`authorities` VALUES (NULL, 'john', 'write'); | |
INSERT IGNORE INTO `spring`.`users` VALUES (NULL, 'john', '12345', '1'); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Configuration | |
public class ProjectConfig extends WebSecurityConfigurerAdapter { | |
@Bean | |
public UserDetailsService userDetailsService(DataSource dataSource) { | |
String usersByUsernameQuery = "select username, password, enabled from spring.users where username = ?"; | |
String authsByUserQuery = "select username, authority from spring.authorities where username = ?"; | |
var userDetailsManager = new JdbcUserDetailsManager(dataSource); | |
userDetailsManager.setUsersByUsernameQuery(usersByUsernameQuery); | |
userDetailsManager.setAuthoritiesByUsernameQuery(authsByUserQuery); | |
return userDetailsManager; | |
} | |
@Bean | |
public PasswordEncoder passwordEncoder() { | |
return NoOpPasswordEncoder.getInstance(); | |
} | |
} |
사용자 관리에 LdapUserDetailsManager 이용
- 스프링 시큐리티는 LDAP용 UserDetailsManager 구현도 제공하며, JdbcUserDetailsManager보다는 덜 이용되지만 사용자 관리를 위해 LDAP 시스템을 통합해야 할 때 유용함
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Configuration | |
public class ProjectConfig extends WebSecurityConfigurerAdapter { | |
@Override | |
@Bean | |
public UserDetailsService userDetailsService() { | |
// 컨텍스트 소스를 생성해 LDAP 서버의 주소 지정 | |
var cs = new DefaultSpringSecurityContextSource("ldap://127.0.0.1:33389/dc=springframework,dc=org"); | |
cs.afterPropertiesSet(); | |
LdapUserDetailsManager manager = new LdapUserDetailsManager(cs); | |
// 사용자 이름 매퍼를 설정해 LdapUserDetailsManager에 사용자를 검색하는 방법 지시 | |
manager.setUsernameMapper( | |
new DefaultLdapUsernameToDnMapper("ou=groups", "uid")); | |
// 앱이 사용자를 검색하는 데 필요한 그룹 검색 기준 설정 | |
manager.setGroupSearchBase("ou=groups"); | |
return manager; | |
} | |
@Bean | |
public PasswordEncoder passwordEncoder() { | |
return NoOpPasswordEncoder.getInstance(); | |
} | |
} |
참고
스프링 시큐리티 인 액션
반응형
'Spring > 스프링 시큐리티 인 액션' 카테고리의 다른 글
[8장] 권한 부여 구성: 제한 적용 (0) | 2025.05.30 |
---|---|
[7장] 권한 부여 구성: 액세스 제한 (0) | 2025.05.30 |
[5장] 인증 구현 (0) | 2025.05.21 |
[4장] 암호 처리 (0) | 2025.05.19 |
[2장] 스프링 시큐리티 기본 구성 (0) | 2025.05.18 |