0. Redis 설치 [EC2+Docker]
✔️redis 이미지 다운
docker pull redis
✔️이미지 파일 확인
docker images
✔️ AWS 보안그룹 인바운드/아웃바인드 설정
✔️ docker를 사용하여 redis 이미지를 만들고 redis 비밀번호를 설정
docker run -p 6379:6379 --name (redis 컨테이너 이름) -d redis:latest --requirepass "(비밀번호)"
ex) docker run -p 6379:6379 --name spring-redis -d redis:latest --requirepass "123456"
✔️ redis-cli에서 인증 후 접속 확인
docker exec -i -t (redis 컨테이너 이름) redis-cli
AUTH (비밀번호)
1. 환경 설정
✔️ 의존성
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
✔️ application.yml 파일 수정
redis:
host: SERVER_HOST
port: 6379
password: PASSWORD
❗ SERVER_HOST: EC2 퍼블릭 IP ❗
❗ PASSWORD : Redis 계정 비밀번호 ❗
✔️RedisConfig.java
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private String redisPort;
@Value("${spring.redis.password}")
private String redisPassword;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(redisHost);
redisStandaloneConfiguration.setPort(Integer.parseInt(redisPort));
redisStandaloneConfiguration.setPassword(redisPassword);
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration);
return lettuceConnectionFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
2. Login 처리
로그인을 하면 현재 로그인한 사용자의 email을 value로 저장하려고 한다.
@Override
public LoginResponse login(LoginRequest loginRequest) {
TokenInfoResponse tokenInfoResponse = this.validateLogin(loginRequest);
return LoginResponse.from(tokenInfoResponse);
}
public TokenInfoResponse validateLogin(LoginRequest loginRequest) {
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword());
Authentication authentication = this.authenticationManagerBuilder.getObject().authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
TokenInfoResponse tokenInfoResponse = this.tokenProvider.createToken(authentication);
//redis에 데이터 저장
redisTemplate.opsForValue().set("RT:" + authentication.getName(),
authentication.getName(),tokenInfoResponse.getRefreshTokenExpirationTime(), TimeUnit.MILLISECONDS);
return tokenInfoResponse;
}
❓왜 저장할 때 key앞에 RT를 붙여주는 걸까?
처음에는 그냥 유저의 이름을 저장했는데 내가 구하고 싶은 것은 현재 로그인 중인 전체 사용자이기 때문이다!
+) 하나의 세션이 각각 string, set, hash로 총 3가지의 데이터 타입으로 저장이 된다.
실제로 이렇게 코드를 짜고 Postman으로 localhost:8080/user/login에 POST요청을 한 후, redis-cli로 확인하면 다음과 같이 데이터가 저장된 것을 확인할 수 있다.
✔️ RT: 사용자 email
세션 Key. string타입
✔️ spring:session:sessions:(session id)
세션 정보가 저장됨. hash타입
✔️ spring:session:sessions:expires:(session id)
세션 만료 키. string타입
✔️ spring:session:expirations:(expire time)
만료시간에 삭제될 세션 정보. set타입
만약 다른 데이터 타입인 'spring:session:sessions:717c7769-cb97-4c93-ab4b-41696b513443'에 get을 하면?
이런 이유가 나오는 이유는 다음과 같다.
레디스는 기본적으로 5가지 타입을 제공하고 있으며 데이터베이스에 한번 타입이 결정된 상태에서 해당 타입과 상관없는 명령을 수행하려고 할때 위와 같은 에러 메시지가 출력된다. 꼭 수행해야되는 명령이라면 기존의 키를 지우면 된다.
Redis support 5 types of data types. You need to know what type of value that key maps to, as for each data type, the command to retrieve it is different.
Here are the commands to retrieve key value:
- if value is of type string -> GET <key>
- if value is of type hash -> HGETALL <key>
- if value is of type lists -> lrange <key> <start> <end>
- if value is of type sets -> smembers <key>
- if value is of type sorted sets -> ZRANGEBYSCORE <key> <min> <max>
command to check the type of value a key mapping to:
- type <key>
즉, 내가 입력한 value(email)를 보려면 get "RT:test003@naver.com" 로 조회해야 한다.
-> RT:*형식인 것만 조회하면 된다!
3. 로그인 되어있는 다른 사용자 보기
public void getActiveUser(String email, List<UserDto.ActiveUserResponse> activeUserResponseList){
// (1) RT:*형식인 Key를 모두 조회
Set<String> redisSessionKeys = redisTemplate.keys("RT:*");
// (2) Key Sets를 이용해 value를 하나씩 조회
for (String redisSessionKey : redisSessionKeys) {
String redisSessionValue = (String)redisTemplate.opsForValue().get(redisSessionKey);
User user = validateEmail(redisSessionValue);
if (user.getEmail().equals(email)) {
continue;
}
UserDto.ActiveUserResponse dto = UserDto.ActiveUserResponse.builder()
.name(user.getName())
.email(user.getEmail())
.imgUrl(user.getUserImage().getImageUrl())
.build();
activeUserResponseList.add(dto);
}
}
❗ redisTemplate.keys("RT:*") : RT:~인 key 모두 조회
❗ redisTemplate.opsForValue().get(redisSessionKey): 해당 key 의 value 데이터 조회
opsForValue()가 궁금해?
참고
'Spring > Redis' 카테고리의 다른 글
[Redis] Redis와 Refresh Token을 이용해서 토큰 재발급 하기 (1) | 2023.05.17 |
---|