์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
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 |
- jvm ๋ฐ๋ฐ๋ฅ๊น์ง ํํค์น๊ธฐ
- aws saa ํฉ๊ฒฉ
- ์คํํ๋ ๋ฏธ์ค
- redis ํ ์คํธ์ฝ๋
- nGrinder
- ํ๋ก๊ทธ๋๋จธ์ค
- docker compose
- JPA
- ํ๋ก๊ทธ๋๋จธ์ค ์ปฌ๋ฌ๋ง๋ถ
- prod docker-compose
- Kafka
- AWS Certified Solutions Architect - Associate
- private subnet ec2 ๋ก์ปฌ ์ ์
- docker ps -a
- aws ์ฟ ํฐ
- ์๋ฒ ํฐ์ง๋ ๋์ปค ์ฌ์คํ
- docker
- ํ์ดํผ๋ฐ์ด์
- redis ์กฐํ
- Codedeploy ์ค๋ฅ
- s3 ์ด๋ฏธ์ง ๋ค์ด๋ก๋
- ํ๋ก๊ทธ๋๋จธ์ค ํฉ์นํ์์๊ธ
- Entity
- ์๋ฐ
- ๋ค์ค ์ปจํ ์ด๋
- ์ ํจ์ค ๋น๋ ์ค๋ฅ
- docker-compose kafka
- s3 ์ด๋ฏธ์ง ์ ์ฅ
- ์ ํจ์ค ์ค์ผ์ค๋ฌ
- s3 log ์ ์ฅ
- Today
- Total
๐๐ข๐๐ โ๐๐๐ ๐๐๐ก๐๐ ๐๐๐๐โง
[Redis] Redis์ ํตํด JWT ๋ก๊ทธ์ธ, ๋ก๊ทธ์์ ๊ตฌํํ๊ธฐ ๋ณธ๋ฌธ
[Redis] Redis์ ํตํด JWT ๋ก๊ทธ์ธ, ๋ก๊ทธ์์ ๊ตฌํํ๊ธฐ
๐คRyusun๐ค 2024. 3. 11. 08:00ํ๋ก์ ํธ์์ JWT์ ์ฌ์ฉํ๋๋ฐ ๋ก๊ทธ์์ ๊ตฌํ์ ์ํด Redis๋ฅผ ์ฌ์ฉํด์ผํ๋ค.
JWT์ ํน์ฑ์ ํ ๋ฒ ๋ฐ๊ธ๋ ํ ํฐ์ ๋ง๋ฃ๋๊ธฐ ์ ๊น์ง ๊ณ์ ์ ํจํ๊ฒ ๋จ์์๊ธฐ๋๋ฌธ์ ๋ก๊ทธ์์์ ์ํด์๋ ์๋ฒ๋ ํด๋น ์ฌ์ฉ์์ ํ ํฐ์ ๋ธ๋๋ฆฌ์คํธ์ ์ถ๊ฐํด์ผ ํ๋ค. Redis๋ ์ด๋ฌํ ๋ธ๋๋ฆฌ์คํธ๋ฅผ ์ฝ๊ฒ ๊ด๋ฆฌํ ์ ์๋ ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฐ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ ๊ณตํ๋ฉฐ, ๋์ ์ฑ๋ฅ์ ์ ๊ณตํ๋ค.
Redis๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ๊ฒ ๋ก๊ทธ์ธ, ๋ก๊ทธ์์์ ๊ตฌํํด๋ณด์.
์์กด์ฑ ์ถ๊ฐ & Redis ์ค์
build.gradle์ redis dependency๋ฅผ ์ถ๊ฐํด์ฃผ์.
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
RedisRepositoryConfig.java
Redis ์ค์ ํ๊ธฐ ์ํ ํด๋์ค์ด๋ค.
@Configuration
@EnableRedisRepositories
public class RedisRepositoryConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
RedisConnectionFactory
RedisConnection์ด ์์ฑ๋์ด Redis ์๋ฒ์์ ํต์ ์ ํ ์ ์๊ฒ ํ๋ค.
RedisTemplate
RedisTemplate ๊ฐ์ฒด๋ฅผ ์ด์ฉํ์ฌ Redis๋ฅผ ์ฌ์ฉํ ์ ์๊ฒํ๋ค. RedisConnection์ ๊ฒฝ์ฐ binary value๋ฅผ ์ฃผ๊ณ ๋ฐ๋๋ฐ RedisTemplate์ ๊ฒฝ์ฐ ๋์ ์์ค์ ์ถ์ํ์ ์ง๋ ฌํ๋ฅผ ์ ๊ณตํ๋ค. RedisTemplate์ ๋ฐ์ดํฐ๋ฅผ ์ง๋ ฌํ / ์ญ์ง๋ ฌํ ํ์ฌ ์ ์ฅ / ์กฐํ๋ฅผ ํ๋ฏ๋ก ์ ์ ํ ์ง๋ ฌํ ๋ฐฉ์์ ์ค์ ํด์ฃผ์ด์ผ ํ๋ค.
setKeySerializer, setValueSerializer ์ค์ ํด์ฃผ๋ ์ด์ ๋ RedisTemplate๋ฅผ ์ฌ์ฉํ ๋ Spring - Redis ๊ฐ ๋ฐ์ดํฐ ์ง๋ ฌํ, ์ญ์ง๋ ฌํ ์ ์ฌ์ฉํ๋ ๋ฐฉ์์ด Jdk ์ง๋ ฌํ ๋ฐฉ์์ด๊ธฐ ๋๋ฌธ์ด๋ค. ๋์์๋ ๋ฌธ์ ๊ฐ ์์ง๋ง redis-cli์ ํตํด ์ง์ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ ค๊ณ ํ ๋ ์์๋ณผ ์ ์๋ ํํ๋ก ์ถ๋ ฅ๋๊ธฐ ๋๋ฌธ์ ์ ์ฉํ ์ค์ ์ด๋ค.
StringRedisSerializer
Redis์ ๋ฌธ์์ด์ ์ ์ฅํ๊ณ ๊ฒ์ํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค. Java์ ๋ฌธ์์ด์ Redis์์ ์ฌ์ฉํ ์ ์๋ ํ์์ผ๋ก ์ง๋ ฌํํ๊ณ , Redis์์ ์ฝ์ ๋ฐ์ดํฐ๋ฅผ ๋ค์ Java์ ๋ฌธ์์ด๋ก ์ญ์ง๋ ฌํํ๋ค.
2. AuthenticationConfig.java
Security + JWT ํ ํฐ ๊ฒ์ฆ์ ํ๋ค.
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class AuthenticationConfig {
private final UserServiceImpl userServiceImpl;
@Value("${jwt.token.secret}")
private String secretKey;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.httpBasic().disable()
.csrf().disable()
.cors().and()
.authorizeRequests()
.antMatchers("/user/signup", "/user/login", "/search/**", "/item/**","/sendmail", "/newpassword")
.permitAll()
.antMatchers(HttpMethod.POST, "/**").authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new JwtFilter(userServiceImpl, secretKey), UsernamePasswordAuthenticationFilter.class)
.build();
}
}
SecurityFilterChain์ JWT ํ ํฐ์ ๊ฒ์ฆํ๋ ํด๋์ค๋ฅผ ๋ฃ์ด์ค๋ค.
3.JwtFilter.java
ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๋ค.
@RequiredArgsConstructor
@Slf4j
public class JwtFilter extends OncePerRequestFilter {
private final UserServiceImpl userServiceImpl;
private final String secretKey;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
final String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
log.info("authorization : {}", authorization);
if(authorization == null || !authorization.startsWith("Bearer")){
log.error("authorization is null or not Bearer");
filterChain.doFilter(request, response);
return;
}
if (authorization.split(" ").length != 2) {
log.error("Token is not valid");
filterChain.doFilter(request, response);
return;
}
// Token ๊บผ๋ด๊ธฐ
String token = authorization.split(" ")[1].trim();
// ํ ํฐ ์ ํจ์ฑ ๊ฒ์ฌ
if (!userServiceImpl.isValid(token)) {
log.error("Logged out user");
filterChain.doFilter(request, response);
return;
}
// UserName Token์์ ๊บผ๋ด๊ธฐ
String userName = JwtUtil.getUserEmail(token, secretKey);
log.info("userName : {}", userName);
//๊ถํ ๋ถ์ฌ
UsernamePasswordAuthenticationToken authenticationToken=
new UsernamePasswordAuthenticationToken(userName, null, List.of(new SimpleGrantedAuthority("USER")));
//Detail์ ๋ฃ์ด์ค๋๋ค.
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
}
}
HTTP ์์ฒญ์์ "Authorization" ํค๋์ ๊ฐ์ ๊ฐ์ ธ์์ ํ ํฐ์ ์ถ์ถํ๋ค. ํด๋น ํ ํฐ์ userServiceImpl.isValid() ๋ฉ์๋๋ฅผ ํตํด ๊ฒ์ฆํ๋ค.
UserServiceImpl.java
๋ก๊ทธ์ธ, ๋ก๊ทธ์์, ํ ํฐ ๊ฒ์ฆ์ ํ๋ค.
์ค์ต์ ์ํด ๋ฐํ๊ฐ์ String ์ผ๋ก ์ค์ ํ์๋ค.
@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final BCryptPasswordEncoder encoder;
private final StringRedisTemplate redisTemplate;
@Value("${jwt.token.secret}")
private String secretKey;
private Long expiredMs = 1000 * 60 * 60 * 24 * 7L; //์ผ์ฃผ์ผ
@Override
public LoginResponseDTO login(String userEmail, String password) {
//userEmail ์์
EntityUser selectedUser = userRepository.findByUserEmail(userEmail)
.orElseThrow(() -> new AppException(ErrorCode.USERMAIL_NOT_FOUND, userEmail + " ์กด์ฌํ์ง ์๋ ํ์์
๋๋ค."));
//password ํ๋ฆผ
if (!encoder.matches(password, selectedUser.getUserPassword())) { //์์ ์ค์. inputpassword, DBpassword
throw new AppException(ErrorCode.INVALID_PASSWORD, "๋น๋ฐ๋ฒํธ๊ฐ ํ๋ ธ์ต๋๋ค.");
}
String token = JwtUtil.createToken(selectedUser.getUserEmail(), secretKey, expiredMs);
// ๋ ๋์ค์ ํค ๋ฒจ๋ฅ ํ์์ผ๋ก ํ์ ์ด๋ฉ์ผ, ํ ํฐ ์ ์ฅ
redisTemplate.opsForValue().set("RT:" + userEmail, token);
return new LoginResponseDTO(selectedUser.getUserName(), token);
}
@Override
public Boolean isValid(String userToken) {
try {
ValueOperations<String, String> logoutValueOperations = redisTemplate.opsForValue();
if(logoutValueOperations.get(userToken) != null){
System.out.println("๋ก๊ทธ์์๋ ํ ํฐ ์
๋๋ค.");
return false;
}
return !Jwts.parser().setSigningKey(secretKey).parseClaimsJws(userToken)
.getBody().getExpiration().before(new Date());
} catch (ExpiredJwtException e) {
e.getMessage();
return false;
}
}
@Override
public String logout(HttpServletRequest request) {
String token = request.getHeader(HttpHeaders.AUTHORIZATION).split(" ")[1].trim();
String userEmail = JwtUtil.getUserEmail(token, secretKey);
System.out.println(userEmail);
if (redisTemplate.opsForValue().get("RT:" + userEmail)!= null) {
redisTemplate.delete("RT:" + userEmail);}
redisTemplate.opsForValue().set(token, "logout");
return "LOGOUT_SUCCESS";
}
}
์ฐ์ redis ์ฐ์ฐํ๊ธฐ์ํด StringRedisTemplate ์์กด์ฑ ์ฃผ์ ์ ํด์ผํ๋ค.
StringRedisTemplate Redis๋ Redis ๋ฐ์ดํฐ ์ ์ฅ์์ ๋ํ ๋ฌธ์์ด ๊ธฐ๋ฐ ์์ ์ ์ํํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
ํ์์ด ๋ก๊ทธ์ธ์ ํ๋ฉด ํ ํฐ์ redis์ key, value ํ์์ผ๋ก ์ด๋ฉ์ผ, ํ ํฐ์ ์ ์ฅํ๋ค.
StringRedisTemplate.opsForValue() ๋ฉ์๋๋ ๋ฌธ์์ด ๊ฐ์ ๋ค๋ฃจ๊ธฐ ์ํ ์ฐ์ฐ์๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฉ์๋์ด๋ค.
set์ ํตํด์ ์ฌ์ฉ์์ ์ด๋ฉ์ผ๊ณผ ํ ํฐ์ ์ ์ฅํ๋ค.
RT๋ "Redis Token"์ ์ถ์ฝ์ด์ด๋ฉฐ, ํ ํฐ ๋ฐ์ดํฐ๋ฅผ ๊ตฌ๋ณํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค. ์ด๋ ๊ฒ ๊ตฌ๋ณํจ์ผ๋ก์จ Redis ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ด์์ ์ฌ๋ฌ ์ข ๋ฅ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ ๋ ํน์ ์ ํ์ ๋ฐ์ดํฐ๋ฅผ ์๋ณํ๊ธฐ ์ฝ๊ฒ ํ ์ ์๋ค.
ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๋ ๋ฉ์๋์ด๋ค.
๋ก๊ทธ์์์ ํ๋ฉด ํ ํฐ์ key๋ก ์ ์ฅํ๋๋ฐ get(ํ ํฐ) ๊ฐ์ด ์๋ค๋ฉด ๋ก๊ทธ์์๋ ํ ํฐ์ด๋ผ๊ณ ์ ์ํด์ค๋ค.
๋ก๊ทธ์์ ๋ฉ์๋์ด๋ค.
์ฐ์ redis์ key๋ก ์ ์ฅํ ์ด๋ฉ์ผ์ ํด๋นํ๋ value ๊ฐ์ด ์๋ค๋ฉด ์ญ์ ํด์ค๋ค.
๊ทธ๋ฆฌ๊ณ ํ ํฐ๊ฐ์ key๋ก ์ ์ฅํ๋ค.
์ ์คํ๋๋์ง ์ค์ต์ ํด๋ณด์.
ํฌ์คํธ๋งจ์ผ๋ก ์ ์ํ ๋ก๊ทธ์ธ์ ํ๋ฉด ํ ํฐ์ ๋ฐํํ๋ค.
redis ์ปจํ ์ด๋๋ก ์ ์ํด์ key๊ฐ์ผ๋ก ์ด๋ฉ์ผ์ด ์ ์ ์ฅ๋์๋์ง ํ์ธํด๋ณด์
docker ps
์คํ์ค์ธ ์ปจํ ์ด๋๋ฅผ ๋ณด์ฌ์ค๋ค.
docker exec -it <container Id> redis-cli --raw
์ด ๋ช ๋ น์ด๋ฅผ ํตํด์ redis ์ปจํ ์ด๋๋ก ์ ์ํ๋ค.
// ๋ชจ๋ Key ์กฐํ
keys *
// key์ ํด๋นํ๋ value ์กฐํ
get <key>
๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํด๋ณด๋ฉด ํ ํฐ์ด ์ ์ ์ฅ๋์๋ค!!
์ด์ ๋ก๊ทธ์์์ ํด๋ณด์
ํฌ์คํธ๋งจ์์ Authorization -> Bearer Token์ ์ ํํ ํ ํฐ์ ์ ๋ ฅํ๋ค.
๋ก๊ทธ์์์ด ๋์์ผ๋ฉด redis๋ก ๊ฐ์ ํด๋น ํ ํฐ์ ์ ์ฅํ์๋์ง ํ์ธํด๋ณด์
redis ์ปจํ ์ด๋์์ ๋ชจ๋ keys ๊ฐ๋ค์ ์กฐํํด๋ณด๋ฉด ํ ํฐ์ด ์ ์ ์ฅ๋๊ฑธ ํ์ธํ ์ ์๋ค.
๋ค์ ์ด ํ ํฐ์ผ๋ก ์ ์์ ์คํํด๋ณด์.
๋ก๊ทธ๋ฅผ ๋ณด๋ฉด ๋ก๊ทธ์์ ํ ํฐ์ด๋ผ๊ณ ์๋ ค์ค๋ค.
๋!!
<์ฃผ์>
ํ๋ก์ ํธ์ฉ์ผ๋ก Redis๋ฅผ ์ฌ์ฉํ์ฌ AWS์ ํตํด ๋ฐฐํฌํ๋ฉด ๊ณผ๊ธ์ด ์์ฒญ ๋์ฌ์์๋ค.
ํ์๋ ์ฝ 250๋ง์ ์ ๋ ๊ณผ๊ธ์ด ๋์จ ๊ฒฝํ์ด ์๋ค...^^;
๋ง์ฝ ํ๋ก์ ํธ๋ฅผ ์ํด redis๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๋ฐฐํฌํํ์๋ ๊ฐ๋ฅํ ๋นจ๋ฆฌ ์๋ฒ๋ฅผ ์ค์ง์ํค๊ณ ๊ผญ ๋ชจ๋ ์๋น์ค๋ฅผ ์ญ์ ํ์!!
์ฐธ๊ณ ํ๋ฉด ์ข์ ์๋ฃ
https://freeblogger.tistory.com/10
์ฐธ๊ณ
https://velog.io/@hkyo96/Spring-RedisTemplate-Serializer-์ค์
'๐ฃ๐ฟ๐ผ๐ด๐ฟ๐ฎ๐บ๐บ๐ถ๐ป๐ด๐ป > ๐๐๐๐ข๐ฌ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Redis] Redis๋ฅผ ์ด์ฉํ์ฌ ๋ฐ์ดํฐ ์บ์ฑ& ์กฐํ ์ฑ๋ฅ ๊ฐ์ ํ๊ธฐ (0) | 2024.03.12 |
---|