카테고리 없음
Implement Email Auth #01
porkbellyYam
2023. 2. 8. 23:07
RedisConfig.java
package dev.aco.back.Utils.Redis;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Value("${dev.aco.redishost}")
private String host;
@Value("${dev.aco.redisport}")
private int port;
@Bean
RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(host);
config.setPort(port);
return new LettuceConnectionFactory(config);
}
@Bean
RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(String.class));
return redisTemplate;
}
}
RedisManager.java
package dev.aco.back.Utils.Redis;
import java.time.Duration;
import java.util.Optional;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import dev.aco.back.Entity.User.Member;
import dev.aco.back.Repository.MemberRepository;
import dev.aco.back.Utils.JWT.JWTManager;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class RedisManager {
private final RedisTemplate<String, String> redisTemplate;
private final MemberRepository mrepo;
private final JWTManager manager;
@Transactional
public void setRefreshToken(String token, Long mid) {
ValueOperations<String, String> refreshToken = redisTemplate.opsForValue();
refreshToken.set(token, mid.toString(), Duration.ofDays(7L));
mrepo.loggedMember(mid, true);
}
@Transactional
public void removeRefreshToken(String refreshToken) {
Optional<String> mid = Optional.ofNullable(redisTemplate.opsForValue().get(refreshToken));
if (mid.isPresent()) {
mrepo.loggedMember(Long.parseLong(mid.get()), false);
redisTemplate.delete(refreshToken);
}
}
@Transactional
public Boolean TokenValidator(String accessToken, String refreshToken) {
Optional<Member> targetMember = mrepo
.findById(Long.parseLong(manager.tokenParser(accessToken).get("userNumber").toString()));
Long accessTokenMemberId = targetMember.orElse(Member.builder().memberId(0L).build()).getMemberId();
Long refreshTokenMemberId = Long
.parseLong(Optional.ofNullable(redisTemplate.opsForValue().get(refreshToken)).orElse("-1"));
if (refreshTokenMemberId == accessTokenMemberId & manager.tokenValidator(refreshToken)
& isLogged(accessToken)) {
return true;
} else {
removeRefreshToken(refreshToken);
mrepo.loggedMember(refreshTokenMemberId, false);
return false;
}
}
public Boolean refreshTokenChecker(String refreshToken) {
return Optional.ofNullable(redisTemplate.opsForValue().get(refreshToken)).isPresent() ? true : false;
}
public Boolean isLogged(String aToken) {
return mrepo.findById(Long.parseLong(manager.tokenParser(aToken).get("userNumber").toString()))
.orElse(Member.builder().memberId(0L).logged(false).build()).getLogged();
}
// 이메일인증 (저장, 유효기간 설정, 삭제)
// Redis에 들어가는 DATA (Key : authnum / Value : email)
public String getEmailData(String key) { // authnum 을 통해 email을 얻는다.
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
return valueOperations.get(key);
}
public void setEmailData(String key, String value) { // authnum 을 통해 email을 얻는다.
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
valueOperations.set(key, value);
}
public void setDataExpire(String key, String value, long expiration) {
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
// expireDuaration 동안 (key, value)를 저장한다.
Duration expireDuration = Duration.ofSeconds(expiration);
valueOperations.set(key, value, expireDuration);
}
public void deleteEmailData(String key) {
// 데이터 삭제
redisTemplate.delete(key);
}
}
내가 이해하고 작성한 Redis를 이용한 이메일 인증의 기본적인 흐름
사용자가 회원가입을 하려고 request를 보내면 EmailController를 통해mailService.sendEmail을 호출합니다.
여기선 인증번호 생성과 해당 이메일이 mailRepository에 존재하는지 확인합니다. 만약 존재한다면 이메일, 인증번호와 인증여부(default = false)를 저장합니다.
해당정보는 Redis에게도 보내집니다. RedisManger를 통해 유효기간 또한 셋팅합니다.
AcoMailSender.send() 매서드를 호출하며 메일을 보냅니다.
메일인증 검사는 EmailController가 요청에 따라 verifyMail을 호출하며 이는 MailService에서 동작됩니다.
보내온 정보들이 Redis 에 들어있는지 확인하기 위해 redisManger.getEmailData를 호출합니다.
delete를 이용해 비워줍니다.
if 조건문을 사용해 결과에 따라 true(인증성공), false(인증실패)를 반환합니다.