Skip to content

Commit

Permalink
Merge pull request #13 from team-REDDI/feat/#12/redis
Browse files Browse the repository at this point in the history
feat : redis 연결
  • Loading branch information
YoungGyo-00 authored Jan 11, 2024
2 parents 6f86e67 + e5aedd0 commit 787531f
Show file tree
Hide file tree
Showing 15 changed files with 136 additions and 36 deletions.
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ dependencies {

implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'

// Swagger 3.0.0
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'

implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-redis'
}

tasks.named('test') {
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/example/reddiserver/common/ApiResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ public static <T> ApiResponse<T> successResponse(T data) {
return new ApiResponse<>(SUCCESS_STATUS, data, null);
}

public static <T> ApiResponse<T> successResponse(T data, String message) {
return new ApiResponse<>(SUCCESS_STATUS, data, message);
}

public static ApiResponse<?> successWithNoContent() {
return new ApiResponse<>(SUCCESS_STATUS, null, null);
}
Expand Down
34 changes: 34 additions & 0 deletions src/main/java/com/example/reddiserver/config/RedisConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.example.reddiserver.config;

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.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String redisHost;

@Value("${spring.data.redis.port}")
private int redisPort;

@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}

@Bean
public RedisTemplate<String, String> redisTemplate() {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();

redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory());

return redisTemplate;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.reddiserver.controller.auth;

import com.example.reddiserver.common.ApiResponse;
import com.example.reddiserver.dto.auth.request.ReissueRequestDto;
import com.example.reddiserver.dto.security.response.TokenDto;
import com.example.reddiserver.service.auth.AuthService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/auth")
public class AuthController {
private final AuthService authService;

@PostMapping("/reissue")
public ApiResponse<TokenDto> reissue(@RequestBody ReissueRequestDto reissueRequestDto) {
return ApiResponse.successResponse(authService.reissue(reissueRequestDto), "Access Token 재발급 성공");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.reddiserver.dto.auth.request;

import lombok.Getter;

@Getter
public class ReissueRequestDto {
private String accessToken;
private String refreshToken;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.reddiserver.dto.security;
package com.example.reddiserver.dto.security.response;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.example.reddiserver.dto.security;
package com.example.reddiserver.dto.security.response;

import lombok.Builder;
import lombok.Getter;
Expand Down
25 changes: 10 additions & 15 deletions src/main/java/com/example/reddiserver/entity/RefreshToken.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
package com.example.reddiserver.entity;

import com.example.reddiserver.entity.base.BaseTimeEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class RefreshToken extends BaseTimeEntity {
@RedisHash(value = "refreshToken", timeToLive = 60*60*24*3)
public class RefreshToken {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String refreshToken;

@Column(nullable = false, unique = true)
private String email;
@Indexed
private String providerId;

@Column(nullable = false)
private String refreshToken;

@Builder
public RefreshToken(String email, String refreshToken) {
this.email = email;
public RefreshToken(String providerId, String refreshToken) {
this.providerId = providerId;
this.refreshToken = refreshToken;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.example.reddiserver.repository;

import com.example.reddiserver.entity.RefreshToken;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> {
Optional<RefreshToken> findByEmail(String email);
@Repository
public interface RefreshTokenRepository extends CrudRepository<RefreshToken, String> {
Optional<RefreshToken> findByProviderId(String providerId);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.example.reddiserver.security.jwt;

import com.example.reddiserver.dto.security.JwtErrorResponse;
import com.example.reddiserver.dto.security.response.JwtErrorResponse;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.MalformedJwtException;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.example.reddiserver.security.jwt;

import com.example.reddiserver.dto.security.TokenDto;
import com.example.reddiserver.dto.security.response.TokenDto;
import com.example.reddiserver.entity.RefreshToken;
import com.example.reddiserver.repository.RefreshTokenRepository;
import io.jsonwebtoken.*;
Expand All @@ -27,7 +27,7 @@
public class TokenProvider implements InitializingBean {
private static final String AUTHORITIES_KEY = "auth";
private static final long ACCESS_TOKEN_EXPIRE_TIME = 1000 * 60 * 30L;
private static final long REFRESH_TOKEN_EXPIRE_TIME = 7 * 242 * 60 * 60 * 1000L;
private static final long REFRESH_TOKEN_EXPIRE_TIME = 60 * 60 * 24 * 3L;

@Value("${spring.jwt.secret}")
private String secret;
Expand Down Expand Up @@ -65,17 +65,18 @@ public TokenDto createAccessToken(Authentication authentication) {
String accessToken = createToken(authentication.getName(), authorities, "access");
String newRefreshToken = createToken(authentication.getName(), authorities, "refresh");

Optional<RefreshToken> oldRefreshToken = refreshTokenRepository.findByEmail(authentication.getName());
Optional<RefreshToken> oldRefreshToken = refreshTokenRepository.findByProviderId(authentication.getName());

if (oldRefreshToken.isPresent()) {
refreshTokenRepository.save(oldRefreshToken.get().updateToken(newRefreshToken));
} else {
RefreshToken refreshToken = RefreshToken.builder()
.email(authentication.getName())
.providerId(authentication.getName())
.refreshToken(newRefreshToken)
.build();

refreshTokenRepository.save(refreshToken);
System.out.println("test");
}

return TokenDto.builder()
Expand Down Expand Up @@ -129,7 +130,7 @@ public boolean validateAccessToken(String accessToken) {
public boolean refreshTokenValidation(String token) {
if (!validateAccessToken(token)) return false;

Optional<RefreshToken> refreshToken = refreshTokenRepository.findByEmail(getEmailFromToken(token));
Optional<RefreshToken> refreshToken = refreshTokenRepository.findByProviderId(getEmailFromToken(token));

return refreshToken.isPresent() && token.equals(refreshToken.get().getRefreshToken());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ public String getAuthority() {

@Override
public String getName() {
return "name";
return member.getProviderId();
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package com.example.reddiserver.security.oauth.handler;

import com.example.reddiserver.dto.security.TokenDto;
import com.example.reddiserver.security.jwt.TokenProvider;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;

Expand All @@ -19,15 +17,17 @@
public class OAuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

private final TokenProvider tokenProvider;
private static final ObjectMapper mapper = new ObjectMapper();

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
TokenDto tokenDto = tokenProvider.createAccessToken(authentication);
// Access, Refresh Token Body 저장
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");

String targetUrl = UriComponentsBuilder.fromUriString(getDefaultTargetUrl())
.queryParam("token", tokenDto)
.build().toUriString();
String tokenDto = mapper.writeValueAsString(tokenProvider.createAccessToken(authentication));
response.getWriter().write(tokenDto);

getRedirectStrategy().sendRedirect(request, response, targetUrl);
response.getWriter().flush();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.example.reddiserver.service.auth;

import com.example.reddiserver.dto.auth.request.ReissueRequestDto;
import com.example.reddiserver.dto.security.response.TokenDto;
import com.example.reddiserver.security.jwt.TokenProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AuthService {
private final TokenProvider tokenProvider;

@Transactional
public TokenDto reissue(ReissueRequestDto reissueRequestDto) {
if (!tokenProvider.refreshTokenValidation(reissueRequestDto.getRefreshToken())) {
throw new RuntimeException("유효하지 않은 Refresh Token 입니다.");
}

Authentication authentication = tokenProvider.getAuthentication(reissueRequestDto.getAccessToken());

return tokenProvider.createAccessToken(authentication);
}
}
4 changes: 4 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ spring:
client-id: ${CLIENT_ID}
client-secret: ${CLIENT_SECRET}
scope: profile, email
data:
redis:
host: ${REDIS_HOST}
port: ${REDIS_PORT}

springdoc:
api-docs:
Expand Down

0 comments on commit 787531f

Please sign in to comment.