사용 기술 스택
Redis
Spring Security
Spring Boot
Spring Session
: provides an API and implementations for managing a user’s session information.
HttpSession
: 문서에서 HttpSession을 Spring Session으로 통합할 수 있다(Spring Session provides transparent integration with HttpSession
)고 하는데, 이게 모듈인지? 아니면 개념적 용어인지? 잘 모르겠다.
Redis를 Spring Session 저장소로 사용하기
Dependencies
dependencies {
implementation 'org.springframework.session:spring-session-data-redis'
}
Configuration
server:
servlet:
session:
timeout: 54000
spring:
main:
allow-bean-definition-overriding: true
session:
store-type: redis
redis:
flush-mode: on_save
namespace: spring:session
redis:
lettuce:
pool:
max-active: 10
max-idle: 10
min-idle: 2
host: localhost
port: 6378
https://docs.spring.io/spring-session/reference/guides/boot-redis.html#boot-spring-configuration
Under the hood, Spring Boot applies configuration that is equivalent to manually adding `@EnableRedisHttpSession` annotation. This creates a Spring bean with the name of `springSessionRepositoryFilter` that implements `Filter`. The filter is in charge of replacing the `HttpSession` implementation to be backed by Spring Session.
이 글에 따르면 spring.session.store-type=redis
를 작성해주면 @EnableRedisHttpSession
없이 configuration을 적용해준다고 하는데 왜인지 연결이 되지 않아 RedisConfig도 작성해주었다.
@EnableRedisHttpSession
은 springSessionRepositoryFilter
Bean을 작성해준다. 이 Bean이 HttpSession을 SpringSession과 통합해주는 역할을 한다.
@EnableSpringHttpSession
@Configuration
public class RedisConfig {
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.host}")
private String host;
@Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory(host, port);
}
@Bean
public HeaderHttpSessionIdResolver httpSessionIdResolver() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
}
@EnableSpringHttpSession
사용시 sessionEventHttpSessionListenerAdapter
Bean을 재정의한다.
⛔ The bean 'sessionEventHttpSessionListenerAdapter', defined in class path resource [org/springframework/boot/autoconfigure/session/RedisSessionConfiguration$SpringBootRedisHttpSessionConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.class] and overriding is disabled.
해당 에러로 spring.main.allow-bean-definition-overriding=true
를 추가해주었다.
How it works?
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final IbAuthenticationEntryPoint authenticationEntryPoint;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/account/logout").authenticated()
.antMatchers("/account/**").permitAll()
.antMatchers("/**").permitAll()
.and().formLogin().disable().csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
return http.build();
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
}
@RequiredArgsConstructor
@RestController
@RequestMapping("/account")
public class AccountController {
private final AccountService accountService;
private final AccountMapper accountMapper;
@PostMapping("/register")
public ResponseEntity<RegisterResponse> register(@RequestBody RegisterRequest registerRequest) {
return ResponseEntity.ok().body(accountService.registerByRegisterRequest(registerRequest));
}
@PostMapping("/login")
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest loginRequest) {
Account account = accountService.loginByLoginRequest(loginRequest);
Authentication authentication = new UsernamePasswordAuthenticationToken(
new IbUserDetails(account.getEmail(), account.getAccountId(), account.getPassword()),
account.getPassword(),
null);
SecurityContextHolder.getContext().setAuthentication(authentication);
return ResponseEntity.ok(accountMapper.accountToLoginResponse(account));
}
@PostMapping("/logout")
public ResponseEntity<Object> logout(HttpSession session) {
session.invalidate();
return ResponseEntity.ok(null);
}
}
Login Flow
- 클라이언트가 login api 를 요청한다.
- DB에서 정보를 확인한다.
정보가 일치하지 않으면 Exception을 띄운다. - SecurityContextHolder에 Authentication 객체를 넣어주고, authenticated 시킨다.
필터에서 Redis에 Session을 저장시킨다. - X-Auth-Token 헤더로 sessionId를 보내준다.
'Backend > Spring' 카테고리의 다른 글
@Transactional 전파 전략 (0) | 2023.05.07 |
---|---|
DI와 IoC (0) | 2023.04.07 |
Spring Container와 Bean의 Lifecycle (0) | 2023.04.07 |
Spring Boot Controller Test (0) | 2023.04.07 |
SpringFox 3.0.0 Server URL Error (0) | 2023.03.03 |