Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/auth/**").permitAll()
.requestMatchers("/api/be/v1/auth/**").permitAll()
.anyRequest().authenticated()
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package marchtue.reuse.trade.domain.model;

public class UserCategory {


}
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,5 @@ public ApiResponse deleteCategory(
) {
return categoryService.deleteCategory(categoryId, request);
}

}
4 changes: 4 additions & 0 deletions Backend/user/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ dependencies {
testImplementation "org.mockito:mockito-core:5.+"
testImplementation 'org.mockito:mockito-junit-jupiter'
testImplementation 'org.assertj:assertj-core'

implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package marchtue.reuse.user.application.dto.response;

import java.math.BigDecimal;

public record MypageResponse(
String nickname,
Long inProgressTrade,
Long completedTrade,
Long token,
BigDecimal rateScore,
String bank,
String account,
String phoneNumber
) {

}
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package marchtue.reuse.user.application.service;

import jakarta.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import marchtue.reuse.user.application.dto.request.CheckUserRequest;
import marchtue.reuse.user.application.dto.request.NicknameCheckRequest;
import marchtue.reuse.user.application.dto.request.UserAddInfoRequest;
import marchtue.reuse.user.application.dto.response.MypageResponse;
import marchtue.reuse.user.domain.enums.UserRoleEnum;
import marchtue.reuse.user.domain.model.Credential;
import marchtue.reuse.user.domain.model.User;
import marchtue.reuse.user.domain.model.UserCategory;
import marchtue.reuse.user.domain.model.UserRating;
import marchtue.reuse.user.domain.model.Wallet;
import marchtue.reuse.user.domain.repository.CredentialRepository;
import marchtue.reuse.user.domain.repository.UserCategoryRepository;
import marchtue.reuse.user.domain.repository.UserRatingRepository;
import marchtue.reuse.user.domain.repository.UserRepository;
import marchtue.reuse.user.domain.repository.WalletRepository;
import marchtue.reuse.user.exception.BusinessException;
import marchtue.reuse.user.exception.ErrorCode;
import marchtue.reuse.user.global.dto.ApiResponse;
import marchtue.reuse.user.global.util.JwtUtil;
import marchtue.reuse.user.global.util.NicknameFilter;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -26,6 +34,9 @@ public class UserService {
private final UserRepository userRepository;
private final CredentialRepository credentialRepository;
private final WalletRepository walletRepository;
private final UserRatingRepository userRatingRepository;
private final UserCategoryRepository userCategoryRepository;
private final JwtUtil jwtUtil;

public ApiResponse checkNickname(NicknameCheckRequest req) {
String nickname = req.nickname();
Expand Down Expand Up @@ -106,6 +117,9 @@ public ApiResponse registerUser(UserAddInfoRequest req) {
savedUser);
walletRepository.save(wallet);
}
// 레이팅 정보 생성
UserRating rating = UserRating.create(savedUser);
userRatingRepository.save(rating);

Map<String, UUID> response = Map.of("user_id", savedUser.getId());

Expand All @@ -125,6 +139,42 @@ public void checkDid(String userId, String did) {
}
}

public ApiResponse myPage(HttpServletRequest request, UUID userId) throws BusinessException {
UUID targetUserId = getUserInfoFromToken(request);
if (!userId.equals(targetUserId)) {
if (checkUserRole(request) == UserRoleEnum.ROLE_USER) {
throw new BusinessException(ErrorCode.FORBIDDEN);
}
}
User user = findById(userId);
UserRating rating = getUserRating(user);
MypageResponse res = new MypageResponse(
user.getNickname(),
rating.getInProgressTrade(),
rating.getCompletedTrade(),
user.getToken(),
rating.getRateScore(),
user.getBank().getKoreanName(),
user.getAccount(),
user.getPhoneNumber()
);
return new ApiResponse(200, "succceded", res);
}

public ApiResponse favCategory(UUID categoryId, HttpServletRequest request) {
UUID userId = getUserInfoFromToken(request);
UserCategory category = userCategoryRepository.findByUserIdAndCategoryId(userId, categoryId)
.orElse(null);
if (category == null) {
UserCategory favCate = UserCategory.create(userId, categoryId);
userCategoryRepository.save(favCate);
} else {
userCategoryRepository.delete(category);
}

return new ApiResponse(200, "succeeded", null);
}

private User findByNickname(String nickname) {
return userRepository.findByNickname(nickname.toLowerCase());
}
Expand All @@ -138,4 +188,28 @@ public User findById(UUID userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
}

private UserRating getUserRating(User user) {
return userRatingRepository.findByUserId(user.getId());
}

private UUID getUserInfoFromToken(HttpServletRequest request) {
String token = jwtUtil.getTokenFromHeader(request, jwtUtil.AUTHORIZATION_HEADER);
if (token == null || !jwtUtil.validateToken(token)) {
throw new BusinessException(ErrorCode.NO_ROLE);
}
return UUID.fromString(jwtUtil.getUserInfoFromToken(token).getSubject());
}

private UserRoleEnum checkUserRole(HttpServletRequest request) {
String token = jwtUtil.getTokenFromHeader(request, JwtUtil.AUTHORIZATION_HEADER);
if (token == null || !jwtUtil.validateToken(token)) {
throw new BusinessException(ErrorCode.NO_ROLE);
}

return jwtUtil.getUserRole(token);

}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package marchtue.reuse.user.domain.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.UuidGenerator;

@Entity
@Table(name = "user_categories", uniqueConstraints = {
@UniqueConstraint(columnNames = {"user_id", "category_id"})
})
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
public class UserCategory {

@Id
@GeneratedValue
@UuidGenerator
private UUID id;

@Column(name = "user_id", nullable = false, columnDefinition = "UUID")
private UUID userId;

@Column(name = "category_id", nullable = false, columnDefinition = "UUID")
private UUID categoryId;

public static UserCategory create(
UUID userId,
UUID categoryId
) {
return UserCategory.builder()
.userId(userId)
.categoryId(categoryId)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,19 @@ public class UserRating extends BaseEntity {
@JoinColumn(name = "user_id")
private User user;


public static UserRating create(
User user
) {
UserRating rating = UserRating.builder()
.inProgressTrade(0L)
.completedTrade(0L)
.totalScore(BigDecimal.ZERO)
.rateScore(BigDecimal.ZERO)
.user(user)
.build();
rating.setCreatedBy(user.getId());
return rating;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package marchtue.reuse.user.domain.repository;

import java.util.Optional;
import java.util.UUID;
import marchtue.reuse.user.domain.model.UserCategory;

public interface UserCategoryRepository {

UserCategory save(UserCategory favCate);

void delete(UserCategory category);

Optional<UserCategory> findByUserIdAndCategoryId(UUID userId, UUID categoryId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package marchtue.reuse.user.domain.repository;

import java.util.UUID;
import marchtue.reuse.user.domain.model.UserRating;

public interface UserRatingRepository {

UserRating save(UserRating rating);

UserRating findByUserId(UUID id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ public enum ErrorCode {
BADWORD_NICKNAME(400, "bad word nickname"),
DUPLICATED_NICKNAME(400, "duplicated nickname"),
EXIST_USER(400, "same hs already exist"),
USER_NOT_FOUND(404, "user not found");
USER_NOT_FOUND(404, "user not found"),
NO_ROLE(400, "theres no role"),
FORBIDDEN(403, "forbidden");


private final int code;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package marchtue.reuse.user.global.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.Base64;
import marchtue.reuse.user.domain.enums.UserRoleEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Component
public class JwtUtil {

public static final Logger logger = LoggerFactory.getLogger("JWT 관련 로그");

public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String REFRESH_TOKEN_COOKIE = "Refresh_Token";
public static final String BEARER_PREFIX = "Bearer ";

@Value("${jwt.secret.key}")
private String secretKey;

private Key key;

@PostConstruct
public void init() {
byte[] bytes = Base64.getDecoder().decode(secretKey);
key = Keys.hmacShaKeyFor(bytes);
}

public boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
return true;
} catch (SecurityException | MalformedJwtException e) {
logger.error("Invalid JWT signature");
} catch (ExpiredJwtException e) {
logger.error("Expired JWT token");
} catch (UnsupportedJwtException e) {
logger.error("Unsupported JWT token");
} catch (IllegalArgumentException e) {
logger.error("JWT claims is empty");
}
return false;
}

public String getTokenFromHeader(HttpServletRequest request, String headerName) {
String headerValue = request.getHeader(headerName);
if (StringUtils.hasText(headerValue) && headerValue.startsWith(BEARER_PREFIX)) {
return headerValue.substring(BEARER_PREFIX.length());
}
return null;
}

public String getTokenFromCookie(HttpServletRequest request, String cookieName) {
if (request.getCookies() != null) {
for (Cookie cookie : request.getCookies()) {
if (cookie.getName().equals(cookieName)) {
return cookie.getValue();
}
}
}
return null;
}

public Claims getUserInfoFromToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
}


public UserRoleEnum getUserRole(String token) {
Claims claims = getUserInfoFromToken(token);
String role = claims.get("role", String.class);
return UserRoleEnum.valueOf(role);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package marchtue.reuse.user.infrastructure;

import java.util.UUID;
import marchtue.reuse.user.domain.model.UserCategory;
import marchtue.reuse.user.domain.repository.UserCategoryRepository;
import org.springframework.data.jpa.repository.JpaRepository;

public interface JpaUserCategoryRepository extends UserCategoryRepository,
JpaRepository<UserCategory, UUID> {

}
Loading