1.레디스 설정
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
// if(mode.equals("1")){
// RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
// clusterConfiguration.clusterNode(host, port);
// LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
// .clientOptions(ClientOptions.builder()
// .socketOptions(SocketOptions.builder()
// .build())
// .build()).build();
// return new LettuceConnectionFactory(clusterConfiguration, clientConfiguration);
// }
return new LettuceConnectionFactory("localhost",6379);
}
@Bean
public RedisTemplate<String,Object> redisTemplate() {
RedisTemplate<String,Object>redisTemplate=new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
}
2.jwt 서비스 작성
@Service
@RequiredArgsConstructor
public class TokenService {
private final RedisTemplate<String, Object> redisTemplate;
private String jwtSecret="jwtSecret";
public String generateToken(String username, long expiration) {
try {
Algorithm algorithm = Algorithm.HMAC512(jwtSecret);
Date expiryDate = new Date(System.currentTimeMillis() + expiration);
return JWT.create()
.withSubject(username)
.withIssuedAt(new Date())
.withExpiresAt(expiryDate)
.sign(algorithm);
} catch (JWTCreationException e) {
throw new RuntimeException("Error creating JWT token", e);
}
}
public void saveRefreshToken(String username, String refreshToken, LocalDateTime issueDate, long issueCount) {
// TokenInfo 객체 생성
Map<String,Object> tokenInfo = new HashMap<>();
tokenInfo.put("id",username);
tokenInfo.put("refreshToken",refreshToken);
tokenInfo.put("issueDate",issueDate.toString());
tokenInfo.put("issueCount",issueCount);
// 여기에서 username을 사용하여 리프레시 토큰 정보를 객체로 직렬화하여 저장
redisTemplate.opsForHash().put("refreshToken"+username, username,tokenInfo);
// 만료 시간 설정 (예: 1시간)
redisTemplate.expire("refreshToken" + username, 1, TimeUnit.HOURS);
}
public Map<String,Object> getRefreshTokenInfo(String username) {
// 여기에서 username을 사용하여 리프레시 토큰 정보를 역직렬화하여 추출
return (Map<String,Object>) redisTemplate.opsForHash().get("refreshToken" + username,username);
}
}
3.로그인 필터 추가 로직 작성
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
log.info("로그인 성공");
// 로그인 성공 시 JWT 토큰 발급
String jwtToken = tokenService.generateToken("access", jwtExpirationInMs);
String refreshToken = tokenService.generateToken("refresh", refreshExpirationInMs);
// JWT 토큰을 응답 쿠키에 추가
ResponseCookie jwtCookie = ResponseCookie.from("access_token", jwtToken)
.path("/")
.httpOnly(true)
.maxAge(jwtExpirationInMs / 1000)
.sameSite("None")
.secure(true)
.build();
response.addHeader("Set-Cookie", jwtCookie.toString());
ResponseCookie refreshCookie = ResponseCookie.from("refresh_token", refreshToken)
.path("/")
.httpOnly(true)
.maxAge(refreshExpirationInMs / 1000)
.sameSite("None")
.secure(true)
.build();
response.addHeader("Set-Cookie", refreshCookie.toString());
// 로그인 성공 시 200 응답 코드만 반환
response.setStatus(HttpServletResponse.SC_OK);
// 응답 본문에 JSON 추가
ObjectMapper objectMapper = new ObjectMapper();
String jsonResponse = objectMapper.writeValueAsString(Map.of("message", "login done"));
response.getWriter().write(jsonResponse);
response.getWriter().flush();
// 로그인 성공한 유저의 이름 얻어내기
SecurityContextHolder.getContext().setAuthentication(authResult);
PrincipalDetails principalDetails = (PrincipalDetails) authResult.getPrincipal();
String username = principalDetails.getUsername();
LocalDateTime issueDate = LocalDateTime.now();
long issueCount = 0;
// 리프레시 토큰 저장
tokenService.saveRefreshToken(username, refreshToken,issueDate,issueCount);
// 시큐리티 세션에 인증 주입
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(principalDetails, null, principalDetails.getAuthorities()));
// 레디스에 저장된 리프레시 토큰 정보 확인
Map<String,Object> savedTokenInfo = tokenService.getRefreshTokenInfo(username);
if (savedTokenInfo != null) {
// 레디스에 저장된 리프레시 토큰 정보가 있는 경우 로그 출력
log.info("Refresh Token Info from Redis: {}", savedTokenInfo);
} else {
// 레디스에 저장된 리프레시 토큰 정보가 없는 경우 로그 출력
log.info("Refresh Token Info not found in Redis for user: {}", username);
}
}
테스트
소스
https://github.com/novb1492/login/tree/set-auth
버그fix
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
log.info("로그인 성공");
// 로그인 성공한 유저의 이름 얻어내기
SecurityContextHolder.getContext().setAuthentication(authResult);
PrincipalDetails principalDetails = (PrincipalDetails) authResult.getPrincipal();
String username = principalDetails.getUsername();
// 로그인 성공 시 JWT 토큰 발급
String jwtToken = tokenService.generateToken(username, jwtExpirationInMs);
String refreshToken = tokenService.generateToken(username, refreshExpirationInMs);
// JWT 토큰을 응답 쿠키에 추가
ResponseCookie jwtCookie = ResponseCookie.from("access_token", jwtToken)
.path("/")
.httpOnly(true)
.maxAge(jwtExpirationInMs * 60)
.sameSite("none")
.secure(true)
.build();
response.addHeader("Set-Cookie", jwtCookie.toString());
ResponseCookie refreshCookie = ResponseCookie.from("refresh_token", refreshToken)
.path("/")
.httpOnly(true)
.maxAge(refreshExpirationInMs*60)
.sameSite("none")
.secure(true)
.build();
response.addHeader("Set-Cookie", refreshCookie.toString());
// 로그인 성공 시 200 응답 코드만 반환
response.setStatus(HttpServletResponse.SC_OK);
// 응답 본문에 JSON 추가
ObjectMapper objectMapper = new ObjectMapper();
String jsonResponse = objectMapper.writeValueAsString(Map.of("message", "login done"));
response.getWriter().write(jsonResponse);
response.getWriter().flush();
LocalDateTime issueDate = LocalDateTime.now();
long issueCount = 0;
// 리프레시 토큰 저장
tokenService.saveRefreshToken(username, refreshToken,issueDate,issueCount);
// 시큐리티 세션에 인증 주입
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(principalDetails, null, principalDetails.getAuthorities()));
// 레디스에 저장된 리프레시 토큰 정보 확인
Map<String,Object> savedTokenInfo = tokenService.getRefreshTokenInfo(username);
if (savedTokenInfo != null) {
// 레디스에 저장된 리프레시 토큰 정보가 있는 경우 로그 출력
log.info("Refresh Token Info from Redis: {}", savedTokenInfo);
} else {
// 레디스에 저장된 리프레시 토큰 정보가 없는 경우 로그 출력
log.info("Refresh Token Info not found in Redis for user: {}", username);
}
}
'짧은 프로젝트' 카테고리의 다른 글
Springboot jwt 로그인5(엑세스 토큰 재발급) (0) | 2024.01.14 |
---|---|
Springboot Jwt 로그인2(로그인 처리 후 쿠키 발급) (0) | 2024.01.12 |
Spring boot jwt 로그인 하기1 (기본세팅) (0) | 2024.01.11 |
Springboot 배달 시스템 만들기 3(위치정보 전송 및 표시하기 카카오지도) (0) | 2024.01.10 |
Springboot 배달 시스템 만들기 2(배달방 생성,삭제,메세지전송) (0) | 2024.01.10 |