티스토리 뷰
반응형
Spring Security
Spring Security의 동작에 대해 이해할려고 많은 문서들을 뒤져봤지만 쉽게 이해할 수 없어 직접 코드를 쓰면서 이해해 보기로 했다. 필자는 Spring Security 를 적용하여 간단한 로그인 인증관련 테스트를 진행할 예정이다.
개발 환경
- IntelliJ IDEA
- Spring Boot 2.6.3
- Java 8
- Gradle
- H2
Gradle 의존성 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
의존성을 추가 했으므로 본격적으로 SecurityConfig 를 작성해보자
@Configuration
@EnableWebSecurity // 해당 어노테이션을 붙인 필터를 스프링 필터 체인에 등록
public class SercurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll() // root 권한에 대한 요청은 허용한다.
.anyRequest().authenticated() // 그 외의 요청에 대해서는 인증이 필요하다.
.and()
.formLogin()
.loginPage("/login") //로그인 페이지로 이동
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/")
.permitAll();
}
@Bean
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
UserDetails build =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(build);
}
}
Spring Security 의존성을 추가하면, 스프링 부트는 그 스프링 시큐리티 자동설정을 적용해줘서, 모든 요청에 대해서 인증을 필요로 하게 된다.
(일부 url을 허용하려면, WebSecurityConfigurerAdapter를 구현하여 설정하면 된다.)
추가로 테스트용 웹 MvcConfig 작성
@Configuration
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
저장할 User 도메인
@Entity
@Getter
@Setter
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
private String password;
private String ROLE;
}
테스트용 Controller
@RestController
public class UserController {
@Autowired
CustomUserService userService;
@GetMapping("/create")
public User create(){
User user = new User();
user.setName("russell");
user.setPassword("password");
user.setROLE("USER");
return userService.save(user);
}
}
/create
호출 시 DB에 User 저장
UserDetailService 를 구현한 CustomUserService
@Service
@RequiredArgsConstructor
public class CustomUserService implements UserDetailsService {
private final UserRepository userRepository;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByName(username);
List<GrantedAuthority> authorityList = new ArrayList<>();
authorityList.add(new SimpleGrantedAuthority("ROLE_USER"));
System.out.println("user = " + user);
return new org.springframework.security.core.userdetails.User(user.getName(),user.getPassword(), authorityList); // User에 해당하는 Model에 UserDetails 구현하여 SpringSecurity 가 이해할 수 있는 형태의 User로 만들어 주어야 한다.
}
public User save(User user) {
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
}
UserDetailService
는 DB로 부터 사용자를 가져와 로그인처리 로직을 구현하는 역할을 한다.- 필자는 loadUserByUsername()을 구현하고, 당연히 return 값으로
UserDetails
를 구현한 객체를 return 했으나, SecurityConfig 의 UserDetailService 와 충돌이 있는 듯 하여 계속 인증이 실패하였다. - SecurityConfig 의 UserDetailService를 주석처리하니 정상적으로 작동하였다.
- 필자는 loadUserByUsername()을 구현하고, 당연히 return 값으로
UserRepository
public interface UserRepository extends JpaRepository<User, Long> {
User findByName(String username);
}
- root로 접속한다.
- /hello로 접속을 요청했지만 허가되지 않은 경로 이므로 /login 페이지로 redirect
- /create 로 접속해 미리 Controller에 입력해 놓은 User를 저장한다.
- 저장한 username 과 password를 입력
- 정상적으로 로그인이 되었다.
마치며
간단한 Spring Security 이용한 로그인을 구현하였으며, 다음으로는 프로젝트에 붙일 Oauth2 Security를 공부하고 적용해 볼 예정이다.
참고
반응형
'Spring Security' 카테고리의 다른 글
Spring Boot OAuth2 소셜 로그인 구현 (3) | 2023.03.15 |
---|---|
Spring Security 용어 및 흐름 이해하기 (0) | 2023.03.03 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- DispatcherServlet
- 논블로킹
- database
- thread
- oauth2
- GIS
- lock
- spring boot
- R-Tree
- jenkins
- 네트워크
- spring
- mysql
- 스프링
- Excel
- github
- TCP
- 다운로드
- 영속성 컨텍스트
- jpa
- 공간쿼리
- 비동기
- 인덱스
- spring mvc
- 쓰레드
- db
- 데이터베이스
- java
- Spring Security
- Index
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함