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 CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();

config.setAllowCredentials(true); // 쿠키나 인증헤더 자격증명 허용
config.setAllowedOrigins(List.of("http://localhost:5173","http://localhost:63342", "https://no-wait-fe-nowait-admin-2y5y.vercel.app", "https://nowait-admin.co.kr")); // 허용할 출처 설정
config.setAllowedOrigins(List.of("http://localhost:5173","http://localhost:63342", "https://no-wait-fe-nowait-admin-2y5y.vercel.app", "https://nowait-admin.co.kr", "https://www.nowait-admin.com")); // 허용할 출처 설정
config.setAllowedMethods(List.of("GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS")); // 메서드 허용
config.setAllowedHeaders(List.of("*")); //클라이언트가 보낼 수 있는 헤더
config.setExposedHeaders(List.of("Authorization")); //클라이언트(브라우저)가 접근할 수 있는 헤더 지정
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.nowait.applicationadmin.user.dto;

import java.time.LocalDateTime;

import com.nowait.common.enums.Role;
import com.nowait.common.enums.SocialType;
import com.nowait.domaincorerdb.user.entity.User;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand Down Expand Up @@ -39,10 +40,13 @@ public class ManagerSignupRequestDto {
public User toEntity() {
return User.builder()
.email(email)
.phoneNumber("")
.password(password)
.nickname(nickname)
.socialType(SocialType.LOCAL)
.role(Role.MANAGER)
.createdAt(LocalDateTime.now())
.updatedAt(LocalDateTime.now())
.build();

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.nowait.applicationuser.oauth.oauth2;

import java.time.LocalDateTime;
import java.util.Optional;

import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
Expand Down Expand Up @@ -50,11 +51,16 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic

User user = User.builder()
.email(oAuth2Response.getEmail())
.phoneNumber("")
.nickname(oAuth2Response.getNickName())
.profileImage(oAuth2Response.getProfileImage())
.socialType(SocialType.KAKAO)
.role(Role.USER) // 일반 유저 설정
.storeId(0L)
.phoneEntered(false)
.isMarketingAgree(false)
.createdAt(LocalDateTime.now())
.updatedAt(LocalDateTime.now())
.build();

userRepository.save(user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ public class OAuth2LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHan
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException {

CustomOAuth2User customUserDetails = (CustomOAuth2User) authentication.getPrincipal();
CustomOAuth2User customUserDetails = (CustomOAuth2User)authentication.getPrincipal();
User user = customUserDetails.getUser();
Long userId = customUserDetails.getUserId();
String role = authentication.getAuthorities().iterator().next().getAuthority();

// JWT 발급
String accessToken = jwtUtil.createAccessToken("accessToken", userId, role, 30 * 60 * 1000L); // 30분
String accessToken = jwtUtil.createAccessToken("accessToken", userId, role,
Boolean.TRUE.equals(user.getPhoneEntered()), Boolean.TRUE.equals(user.getIsMarketingAgree()),60 * 60 * 1000L); // 1시간
String refreshToken = jwtUtil.createRefreshToken("refreshToken", userId, 30L * 24 * 60 * 60 * 1000L); // 30일

// 1. refreshToken을 DB에 저장 or update
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ public JwtUtil(@Value("${jwt.secret}") String secret) {
);
}

public String createAccessToken(String tokenCategory, Long userId, String role, Long expiredMs) {
public String createAccessToken(String tokenCategory, Long userId, String role, boolean phoneEntered,
boolean marketingAgree, Long expiredMs) {
return Jwts.builder()
.claim("tokenCategory", tokenCategory) // accessToken
.claim("userId", userId)
.claim("role", role)
.claim("phoneEntered", phoneEntered)
.claim("marketingAgree", marketingAgree)
.issuedAt(new Date(System.currentTimeMillis()))
.expiration(new Date(System.currentTimeMillis() + expiredMs))
.signWith(secretKey)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
import com.nowait.applicationuser.security.jwt.JwtUtil;
import com.nowait.applicationuser.token.dto.AuthenticationResponse;
import com.nowait.applicationuser.token.service.TokenService;
import com.nowait.domaincorerdb.user.entity.User;
import com.nowait.domaincorerdb.user.exception.UserNotFoundException;
import com.nowait.domaincorerdb.user.repository.UserRepository;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
Expand All @@ -22,37 +25,57 @@
@RequestMapping("/api/refresh-token")
@Slf4j
public class TokenController {
private final JwtUtil jwtUtil;
private final TokenService tokenService;
@Value("${jwt.access-token-expiration-ms}")
private long accessTokenExpiration;
@Value("${jwt.refresh-token-expiration-ms}")
private long refreshTokenExpiration;

@PostMapping
@Operation(summary = "리프레시 토큰", description = "리프레시 토큰을 사용하여 새로운 액세스 토큰과 리프레시 토큰을 발급합니다.")
@ApiResponse(responseCode = "200", description = "새로운 액세스 토큰과 리프레시 토큰 발급 성공")
public ResponseEntity<?> refreshToken(
@CookieValue(value = "refreshToken", required = false) String refreshToken) {

if (refreshToken == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Refresh token not found in cookies");
}

// 리프레시 토큰 검증
Long userId = jwtUtil.getUserId(refreshToken);
String role = jwtUtil.getRole(refreshToken);

if (tokenService.validateToken(refreshToken, userId)){
String newAccessToken = jwtUtil.createAccessToken("accessToken", userId, role, accessTokenExpiration);
String newRefreshToken = jwtUtil.createRefreshToken("refreshToken", userId, refreshTokenExpiration);

tokenService.updateRefreshToken(userId, refreshToken, newRefreshToken);

AuthenticationResponse authenticationResponse = new AuthenticationResponse(newAccessToken, newRefreshToken);
return ResponseEntity.ok().body(authenticationResponse);
}

return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid or expired refresh token");
}
private final JwtUtil jwtUtil;
private final TokenService tokenService;
private final UserRepository userRepository;
@Value("${jwt.access-token-expiration-ms}")
private long accessTokenExpiration;
@Value("${jwt.refresh-token-expiration-ms}")
private long refreshTokenExpiration;

@PostMapping
@Operation(summary = "리프레시 토큰", description = "리프레시 토큰을 사용하여 새로운 액세스 토큰과 리프레시 토큰을 발급합니다.")
@ApiResponse(responseCode = "200", description = "새로운 액세스 토큰과 리프레시 토큰 발급 성공")
public ResponseEntity<?> refreshToken(
@CookieValue(value = "refreshToken", required = false) String refreshToken) {

if (refreshToken == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Refresh token not found in cookies");
}

// 리프레시 토큰 검증
Long userId;
String role;
try {
userId = jwtUtil.getUserId(refreshToken);
role = jwtUtil.getRole(refreshToken);
} catch (RuntimeException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid or expired refresh token");
}

User user = userRepository.findById(userId).orElseThrow(UserNotFoundException::new);

if (tokenService.validateToken(refreshToken, userId)) {
String newAccessToken = jwtUtil.createAccessToken(
"accessToken",
userId,
role,
Boolean.TRUE.equals(user.getPhoneEntered()),
Boolean.TRUE.equals(user.getIsMarketingAgree()),
accessTokenExpiration
);
String newRefreshToken = jwtUtil.createRefreshToken(
"refreshToken",
userId,
refreshTokenExpiration
);

tokenService.updateRefreshToken(userId, refreshToken, newRefreshToken);

AuthenticationResponse authenticationResponse = new AuthenticationResponse(newAccessToken, newRefreshToken);
return ResponseEntity.ok().body(authenticationResponse);
}

return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid or expired refresh token");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.nowait.applicationuser.user.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.nowait.applicationuser.user.dto.UserUpdateRequest;
import com.nowait.applicationuser.user.service.UserService;
import com.nowait.common.api.ApiUtils;
import com.nowait.domainuserrdb.oauth.dto.CustomOAuth2User;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {

private final UserService userService;

@PutMapping("/optional-info")
public ResponseEntity<?> putOptional(
@AuthenticationPrincipal CustomOAuth2User customOAuth2User,
@Valid @RequestBody UserUpdateRequest req) {

String newAccessToken = userService.putOptional(customOAuth2User.getUserId(), req.phoneNumber(),
Boolean.TRUE.equals(req.consent()));

return ResponseEntity
.status(HttpStatus.OK)
.body(
ApiUtils.success(
newAccessToken
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.nowait.applicationuser.user.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;

public record UserUpdateRequest(
@NotBlank
@Pattern(regexp = "^010-\\d{4}-\\d{4}$", message = "휴대폰 번호는 010-0000-0000 형식이어야 합니다.")
String phoneNumber,
boolean consent) { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.nowait.applicationuser.user.service;

import java.time.LocalDateTime;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.nowait.applicationuser.security.jwt.JwtUtil;
import com.nowait.domaincorerdb.user.entity.User;
import com.nowait.domaincorerdb.user.exception.UserNotFoundException;
import com.nowait.domaincorerdb.user.repository.UserRepository;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class UserService {

private final UserRepository userRepository;
private final JwtUtil jwtUtil;

@Transactional
public String putOptional(Long userId, String phoneNumber, boolean consent) {

User user = userRepository.findById(userId)
.orElseThrow(UserNotFoundException::new);

if (userRepository.existsByPhoneNumberAndIdNot(phoneNumber, userId)) {
throw new IllegalArgumentException("이미 사용 중인 휴대폰 번호입니다.");
}

user.setPhoneNumberAndMarkEntered(phoneNumber, LocalDateTime.now());
user.setIsMarketingAgree(consent, LocalDateTime.now());

String role = "ROLE_" + user.getRole().name();

return jwtUtil.createAccessToken("accessToken", user.getId(), role,
Boolean.TRUE.equals(user.getPhoneEntered()),
Boolean.TRUE.equals(user.getIsMarketingAgree()),
60 * 60 * 1000L);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ public class Store extends BaseTimeEntity {
@Column(nullable = true, length = 200)
private String location;

@Column(nullable = true, length = 200)
@Column(nullable = true, length = 250)
private String description;

@Column(nullable = true, length = 200)
private String noticeTitle;

@Column(nullable = true, length = 200)
@Column(nullable = true, length = 500)
private String noticeContent;

@Column(nullable = true, length = 200)
Expand Down
Loading