Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pipeline {
parameters {
gitParameter branch: '',
branchFilter: '.*',
defaultValue: 'origin/main',
defaultValue: 'develop',
description: '', listSize: '0',
name: 'TAG',
quickFilterEnabled: false,
Expand All @@ -26,15 +26,13 @@ pipeline {
}

environment {
GIT_URL = "https://github.com/whl5105/UserService.git"
GIT_URL = "https://github.com/PersonalizedNews-MSA/UserService.git"
GITHUB_CREDENTIAL = "github-token"
ARTIFACTS = "build/libs/**"
DOCKER_REGISTRY = "suin4328"
DOCKERHUB_CREDENTIAL = 'dockerhub-token'

KAFKA_BROKER = "${params.KAFKA_BROKER}" // Jenkins UI Parameter 등록
}

options {
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: "30", artifactNumToKeepStr: "30"))
Expand Down Expand Up @@ -81,7 +79,7 @@ pipeline {

stage('Build & Test Application') {
steps {
sh 'export GRADLE_OPTS="-Xmx2g -Dfile.encoding=UTF-8" && gradle clean build'
sh "gradle clean build"
}
}

Expand All @@ -93,14 +91,14 @@ pipeline {
}
}


stage('Push Docker Image') {
steps {
script {
docker.withRegistry("", DOCKERHUB_CREDENTIAL) {
docker.image("${DOCKER_IMAGE_NAME}").push()
sh "docker buildx build --platform linux/amd64,linux/arm64 -t ${DOCKER_IMAGE_NAME} --push ."
}

sh "docker rmi ${DOCKER_IMAGE_NAME}"
sh "docker rmi -f ${DOCKER_IMAGE_NAME}"
}
}
}
Expand Down
11 changes: 10 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
}

group = 'com.mini2'
version = '0.0.1'
version = '0.0.2'

java {
toolchain {
Expand All @@ -23,6 +23,10 @@ repositories {
mavenCentral()
}

ext {
set('springCloudVersion', "2025.0.0")
}

dependencies {
//jwt
implementation 'io.jsonwebtoken:jjwt-api:0.12.5'
Expand All @@ -46,6 +50,11 @@ dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}

tasks.named('test') {
useJUnitPlatform()
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/com/mini2/user_service/api/BackendK8sController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.mini2.user_service.api;

import com.mini2.user_service.common.dto.ApiResponseDto;
import com.mini2.user_service.service.probe.ProbeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping(value = "/backend/user/v1/k8s", produces = MediaType.APPLICATION_JSON_VALUE)
@RequiredArgsConstructor
public class BackendK8sController {
private final ProbeService probeService;

@GetMapping(value = "/liveness")
public ApiResponseDto<String> liveness() {
probeService.validateLiveness();
return ApiResponseDto.defaultOk();
}

@GetMapping(value = "/readiness")
public ApiResponseDto<String> readiness() {
probeService.validateReadiness();
return ApiResponseDto.defaultOk();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,21 @@ public class UserAuthController {
private final RefreshTokenService refreshTokenService;

@Operation(summary = "회원가입", description = "이름, 이메일, 비밀번호를 입력받아 회원가입을 진행합니다.")
@PostMapping(value = "/signup")
public ApiResponseDto<String> register(@RequestBody @Valid UserRegisterRequestDto registerDto) {
userAuthService.registerUser(registerDto);
return ApiResponseDto.defaultOk();
@PostMapping(value = "/auth/signup")
public ApiResponseDto<TokenDto.AccessToken> register(@RequestBody @Valid UserRegisterRequestDto registerDto , HttpServletResponse response) {
String deviceInfo = GatewayRequestHeaderUtils.getClientDeviceOrThrowException();
TokenDto.AccessRefreshToken token = userAuthService.registerUser(registerDto , deviceInfo);
CookieUtils.addCookie(response, "refreshToken", token.getRefreshToken().getToken(), token.getRefreshToken().getExpiresIn());
return ApiResponseDto.createOk(new TokenDto.AccessToken(token.getAccessToken()));
}

@Operation(summary = "사용자 로그인", description = "이메일과 비밀번호를 입력받아 JWT 액세스/리프레시 토큰을 반환합니다.")
@PostMapping(value = "/login")
@PostMapping(value = "/auth/login")
public ApiResponseDto<TokenDto.AccessToken> login(@RequestBody @Valid UserLoginRequestDto loginDto, HttpServletResponse response , HttpServletRequest request) {
String deviceInfo = GatewayRequestHeaderUtils.getClientDeviceOrThrowException();
TokenDto.AccessRefreshToken token = userAuthService.login(loginDto , deviceInfo);
CookieUtils.addCookie(response, "refreshToken", token.getRefresh().getToken(), token.getRefresh().getExpiresIn());
return ApiResponseDto.createOk(new TokenDto.AccessToken(token.getAccess()));
CookieUtils.addCookie(response, "refreshToken", token.getRefreshToken().getToken(), token.getRefreshToken().getExpiresIn());
return ApiResponseDto.createOk(new TokenDto.AccessToken(token.getAccessToken()));
}

@Operation(summary = "AccessToken 재발급", description = "만료된 AccessToken을 리프레시 토큰을 통해 재발급합니다.")
Expand All @@ -54,10 +56,9 @@ public ApiResponseDto<TokenDto.AccessToken> refreshToken(HttpServletRequest requ

@Operation(summary = "로그아웃", description = "리프레시 토큰을 비활성화 하고 쿠키 삭제를 통해 로그아웃을 처리합니다.")
@PostMapping("/logout")
public ApiResponseDto<String> logout(HttpServletRequest request, HttpServletResponse response) {
String refreshToken = CookieUtils.extractRefreshToken(request);
String deviceInfo = GatewayRequestHeaderUtils.getClientDeviceOrThrowException();
userAuthService.logout(refreshToken, deviceInfo);
public ApiResponseDto<String> logout(HttpServletResponse response) {
Long userId = Long.valueOf(GatewayRequestHeaderUtils.getUserIdOrThrowException());
userAuthService.logout(userId);
CookieUtils.deleteCookie(response,"refreshToken");
return ApiResponseDto.createOk("로그아웃 되었습니다.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class UserController {
private final UserService userService;

@Operation(summary = "이메일 중복 확인", description = "이메일이 이미 존재하는지 확인합니다.")
@PostMapping("/email-check")
@PostMapping("/auth/email-check")
public ApiResponseDto<Boolean> checkEmail(@RequestBody @Valid EmailCheckRequestDto emailCheckDto){
boolean isAvailable = userService.isEmailAvailable(emailCheckDto);
return ApiResponseDto.createOk(isAvailable);
Expand All @@ -50,9 +50,8 @@ public ApiResponseDto<String> updateUser( @RequestBody @Valid UserUpdateRequestD
@Operation(summary = "회원 탈퇴", description = "현재 로그인된 사용자의 계정을 탈퇴 처리합니다.")
@DeleteMapping("/signout")
public ApiResponseDto<String> withdraw(HttpServletRequest request, HttpServletResponse response) {
String refreshToken = CookieUtils.extractRefreshToken(request);
String deviceInfo = GatewayRequestHeaderUtils.getClientDeviceOrThrowException();
userService.withdrawByRequest(refreshToken , deviceInfo);
Long userId = Long.valueOf(GatewayRequestHeaderUtils.getUserIdOrThrowException());
userService.withdrawByRequest(userId);
CookieUtils.deleteCookie(response,"refreshToken");
return ApiResponseDto.createOk("탈퇴 되었습니다.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public TokenDto.JwtToken generateJwtToken(Long userId, String deviceType, boolea
String token = Jwts.builder()
.issuer("welab")
.subject(String.valueOf(userId))
.claim("userId", userId)
.claim("userId", String.valueOf(userId))
.claim("deviceType", deviceType)
.claim("tokenType", tokenType)
.issuedAt(new Date())
Expand Down Expand Up @@ -111,7 +111,7 @@ private Claims verifyAndGetClaims(String token) {
//== JWT의 만료 시간(expiration time) 계산 ==
private int tokenExpiresIn(boolean refreshToken, String deviceType) {
if(!refreshToken){
return 60 * 15;
return 60 * 60;
}
if(deviceType.equals("MOBILE")){
return configProperties.getMobileExpiresIn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ public static class JwtToken {
@Getter
@RequiredArgsConstructor
public static class AccessToken {
private final JwtToken access;
private final JwtToken accessToken;
}

@Getter
@Setter
@RequiredArgsConstructor
public static class AccessRefreshToken {
private final JwtToken access;
private final JwtToken refresh;
private final JwtToken accessToken;
private final JwtToken refreshToken;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,9 @@ public TokenDto.AccessToken reissueAccessToken(String refreshTokenValue, String


// 로그아웃
public void logout(Long userId, String deviceInfo) {
RefreshToken token = refreshTokenRepository.findByUserIdAndDeviceInfo(userId, deviceInfo)
public void logout(Long userId) {
RefreshToken token = refreshTokenRepository.findByUserId(userId)
.orElseThrow(() -> new NotFound("해당 사용자의 토큰이 없습니다."));

token.invalidate();
}

Expand Down
21 changes: 11 additions & 10 deletions src/main/java/com/mini2/user_service/service/UserAuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class UserAuthService {
private final RefreshTokenService refreshTokenService;

//회원가입
public void registerUser(UserRegisterRequestDto registerDto) {
public TokenDto.AccessRefreshToken registerUser(UserRegisterRequestDto registerDto ,String deviceInfo ) {
String email = registerDto.getEmail().toLowerCase();

Optional<User> optionalUser = userRepository.findByEmail(email);
Expand All @@ -36,6 +36,11 @@ public void registerUser(UserRegisterRequestDto registerDto) {

User user = User.create(email, registerDto.getPassword(), registerDto.getName());
userRepository.save(user);

TokenDto.AccessRefreshToken token = tokenGenerator.generateAccessRefreshToken(user.getId(), "WEB");
refreshTokenService.saveToken(user.getId(), token.getRefreshToken() , deviceInfo);
return token;

}

// 로그인
Expand All @@ -49,19 +54,15 @@ public TokenDto.AccessRefreshToken login(UserLoginRequestDto loginDto, String de
throw new BadParameter("아이디 또는 비밀번호를 확인하세요.");
}
TokenDto.AccessRefreshToken token = tokenGenerator.generateAccessRefreshToken(user.getId(), "WEB");
refreshTokenService.saveToken(user.getId(), token.getRefresh() , deviceInfo);
refreshTokenService.saveToken(user.getId(), token.getRefreshToken() , deviceInfo);
return token;
}

//로그아웃
public void logout(String refreshToken, String deviceInfo) {
String userIdStr = tokenGenerator.validateJwtToken(refreshToken);
if (userIdStr == null) {
throw new BadParameter("유효하지 않은 토큰입니다.");
}
Long userId = Long.parseLong(userIdStr);

refreshTokenService.logout(userId, deviceInfo);
public void logout(Long userId) {
userRepository.findById(userId)
.orElseThrow(() -> new NotFound("유저를 찾을 수 없습니다."));
refreshTokenService.logout(userId);
}


Expand Down
9 changes: 2 additions & 7 deletions src/main/java/com/mini2/user_service/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,11 @@ public void updateUserInfo(Long userId,UserUpdateRequestDto userDto) {
}

//회원 탈퇴
public void withdrawByRequest(String refreshToken ,String deviceInfo) {
String userIdStr = tokenGenerator.validateJwtToken(refreshToken);

if (userIdStr == null) throw new BadParameter("잘못된 토큰입니다.");
Long userId = Long.parseLong(userIdStr);

public void withdrawByRequest(Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new NotFound("유저를 찾을 수 없습니다."));

user.markAsDeleted();
refreshTokenService.logout(userId, deviceInfo);
refreshTokenService.logout(userId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.mini2.user_service.service.probe;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class ProbeService {

public void validateLiveness() {
// TODO: 만일 서비스를 재시작 해야 하는 상황이면 exception 발생
}

public void validateReadiness() {
// TODO: 만일 서비스 수행일 일시 중지해야 하는 상황이면 exception 발생
}

}
5 changes: 5 additions & 0 deletions src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
spring:
config:
import:
- file:/etc/config/application-dev.yml
- file:/etc/secret/application-secret.yml
2 changes: 1 addition & 1 deletion src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
server:
port: 8080
port: 8081

spring:
datasource:
Expand Down