Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

9주차 미션 / 서버 2조 강상민 #7

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
Original file line number Diff line number Diff line change
@@ -1,30 +1,55 @@
package kuit3.backend.common.argument_resolver;

import jakarta.servlet.http.HttpServletRequest;
import kuit3.backend.common.exception.jwt.unauthorized.JwtInvalidTokenException;
import kuit3.backend.jwt.JwtProvider;
import kuit3.backend.service.AuthService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.security.access.prepost.PreAuthorize;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolver에서 현재 hasAnnotation으로 해당 어노테이션인지를 확인을 합니다. 하지만 현재 import 해오는 클래스를 보면 저희가 만든 어노테이션이 아닌 spring security에서 제공하는 어노테이션을 가져와서 사용하고 있습니다. 아마 두 개의 어노테이션이 다르기에 false가 나오는 문제가 발생하는 것으로 보입니다.

import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import static kuit3.backend.common.response.status.BaseExceptionResponseStatus.INVALID_TOKEN;

@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthHandlerArgumentResolver implements HandlerMethodArgumentResolver {

private final JwtProvider jwtProvider;
private final AuthService authService;

@Override
public boolean supportsParameter(MethodParameter parameter) {
log.info(parameter.getParameterName() + parameter.getParameterType());
boolean hasAnnotation = parameter.hasParameterAnnotation(PreAuthorize.class);
boolean hasType = long.class.isAssignableFrom(parameter.getParameterType());
boolean hasType = Long.class.isAssignableFrom(parameter.getParameterType());
log.info("hasAnnotation={}, hasType={}, hasAnnotation && hasType={}", hasAnnotation, hasType, hasAnnotation&&hasType);
return hasAnnotation && hasType;
return true;
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
public Object resolveArgument(@NonNull MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
log.info("userId={}", request.getAttribute("userId"));
return request.getAttribute("userId");
String accessToken = (String)request.getAttribute("jwtToken");

String email = jwtProvider.getPrincipal(accessToken);
validatePayload(email);

return authService.getUserIdByEmail(email);
}

private void validatePayload(String email) {
if (email == null) {
throw new JwtInvalidTokenException(INVALID_TOKEN);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package kuit3.backend.common.exception;

import kuit3.backend.common.response.status.ResponseStatus;
import lombok.Getter;

@Getter
public class RestaurantException extends RuntimeException {

private final ResponseStatus exceptionStatus;

public RestaurantException(ResponseStatus exceptionStatus) {
super(exceptionStatus.getMessage());
this.exceptionStatus = exceptionStatus;
}

public RestaurantException(ResponseStatus exceptionStatus, String message) {
super(message);
this.exceptionStatus = exceptionStatus;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package kuit3.backend.common.exception_handler;

import jakarta.annotation.Priority;
import kuit3.backend.common.exception.RestaurantException;
import kuit3.backend.common.response.BaseErrorResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import static kuit3.backend.common.response.status.BaseExceptionResponseStatus.INVALID_RESTAURANT_VALUE;

@Slf4j
@Priority(0)
@RestControllerAdvice
public class RestaurantExceptionControllerAdvice {

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(RestaurantException.class)
public BaseErrorResponse handle_RestaurantException(RestaurantException e) {
log.error("[handle_RestaurantException]", e);
return new BaseErrorResponse(INVALID_RESTAURANT_VALUE, e.getMessage());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import kuit3.backend.common.exception.jwt.bad_request.JwtUnsupportedTokenException;
import kuit3.backend.jwt.JwtProvider;
import kuit3.backend.service.AuthService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
Expand All @@ -27,16 +28,11 @@ public class JwtAuthInterceptor implements HandlerInterceptor {
private final AuthService authService;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
String accessToken = resolveAccessToken(request);
validateAccessToken(accessToken);
request.setAttribute("jwtToken", accessToken);

String email = jwtProvider.getPrincipal(accessToken);
validatePayload(email);

long userId = authService.getUserIdByEmail(email);
request.setAttribute("userId", userId);
return true;
}

Expand All @@ -61,10 +57,4 @@ private void validateAccessToken(String accessToken) {
}
}

private void validatePayload(String email) {
if (email == null) {
throw new JwtInvalidTokenException(INVALID_TOKEN);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ public enum BaseExceptionResponseStatus implements ResponseStatus {
USER_NOT_FOUND(4003, HttpStatus.BAD_REQUEST.value(), "존재하지 않는 회원입니다."),
PASSWORD_NO_MATCH(4004, HttpStatus.BAD_REQUEST.value(), "비밀번호가 일치하지 않습니다."),
INVALID_USER_STATUS(4005, HttpStatus.BAD_REQUEST.value(), "잘못된 회원 status 값입니다."),
EMAIL_NOT_FOUND(4006, HttpStatus.BAD_REQUEST.value(), "존재하지 않는 이메일입니다.");
EMAIL_NOT_FOUND(4006, HttpStatus.BAD_REQUEST.value(), "존재하지 않는 이메일입니다."),

// 6000: Restaurant 오류
INVALID_RESTAURANT_VALUE(6000, HttpStatus.BAD_REQUEST.value(), "식당의 정보가 유효하지 않습니다.");

private final int code;
private final int status;
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/kuit3/backend/config/WebConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ public class WebConfig implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtAuthenticationInterceptor)
.order(1)
.addPathPatterns("/auth/test");
.addPathPatterns("/auth/test")
.addPathPatterns(("/users/**"))
.addPathPatterns("/restaurants")
.excludePathPatterns("/users");
}

@Override
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/kuit3/backend/controller/RestaurantController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package kuit3.backend.controller;

import kuit3.backend.common.argument_resolver.PreAuthorize;
import kuit3.backend.common.exception.RestaurantException;
import kuit3.backend.common.response.BaseResponse;
import kuit3.backend.dto.restaurant.GetRestaurantResponse;
import kuit3.backend.dto.restaurant.PostRestaurantRequest;
import kuit3.backend.service.RestaurantService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

import static kuit3.backend.common.response.status.BaseExceptionResponseStatus.INVALID_RESTAURANT_VALUE;
import static kuit3.backend.util.BindingResultUtils.getErrorMessages;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/restaurants")
public class RestaurantController {

private final RestaurantService restaurantService;

@PostMapping("")
public BaseResponse<Long> makeNewRestaurant(@Validated @RequestBody PostRestaurantRequest postRestaurantRequest, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
throw new RestaurantException(INVALID_RESTAURANT_VALUE, getErrorMessages(bindingResult));
}
return new BaseResponse<>(restaurantService.makeNewRestaurant(postRestaurantRequest));
}

@GetMapping("")
public BaseResponse<List<GetRestaurantResponse>> getRestaurant(
@RequestParam(required = false) Double star,
@RequestParam(required = false) Long lastId) {
return new BaseResponse<>(restaurantService.getRestaurants(star, lastId));
}

}
18 changes: 10 additions & 8 deletions src/main/java/kuit3/backend/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package kuit3.backend.controller;

import kuit3.backend.common.argument_resolver.PreAuthorize;
import kuit3.backend.common.exception.UserException;
import kuit3.backend.common.exception.jwt.unauthorized.JwtInvalidTokenException;
import kuit3.backend.common.exception.jwt.unauthorized.JwtUnauthorizedTokenException;
import kuit3.backend.common.response.BaseResponse;
import kuit3.backend.dto.user.*;
import kuit3.backend.service.UserService;
Expand All @@ -12,8 +15,7 @@

import java.util.List;

import static kuit3.backend.common.response.status.BaseExceptionResponseStatus.INVALID_USER_STATUS;
import static kuit3.backend.common.response.status.BaseExceptionResponseStatus.INVALID_USER_VALUE;
import static kuit3.backend.common.response.status.BaseExceptionResponseStatus.*;
import static kuit3.backend.util.BindingResultUtils.getErrorMessages;

@Slf4j
Expand All @@ -38,26 +40,26 @@ public BaseResponse<PostUserResponse> signUp(@Validated @RequestBody PostUserReq
/**
* 회원 휴면
*/
@PatchMapping("/{userId}/dormant")
public BaseResponse<Object> modifyUserStatus_dormant(@PathVariable long userId) {
@PatchMapping("/dormant")
public BaseResponse<Object> modifyUserStatus_dormant(@PreAuthorize Long userId) {
userService.modifyUserStatus_dormant(userId);
return new BaseResponse<>(null);
}

/**
* 회원 탈퇴
*/
@PatchMapping("/{userId}/deleted")
public BaseResponse<Object> modifyUserStatus_deleted(@PathVariable long userId) {
@PatchMapping("/deleted")
public BaseResponse<Object> modifyUserStatus_deleted(@PreAuthorize long userId) {
userService.modifyUserStatus_deleted(userId);
return new BaseResponse<>(null);
}

/**
* 닉네임 변경
*/
@PatchMapping("/{userId}/nickname")
public BaseResponse<String> modifyNickname(@PathVariable long userId,
@PatchMapping("/nickname")
public BaseResponse<String> modifyNickname(@PreAuthorize long userId,
@Validated @RequestBody PatchNicknameRequest patchNicknameRequest, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
throw new UserException(INVALID_USER_VALUE, getErrorMessages(bindingResult));
Expand Down
55 changes: 55 additions & 0 deletions src/main/java/kuit3/backend/dao/RestaurantDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package kuit3.backend.dao;

import kuit3.backend.dto.restaurant.GetRestaurantResponse;
import kuit3.backend.dto.restaurant.PostRestaurantRequest;
import kuit3.backend.dto.user.GetUserResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Repository
public class RestaurantDao {

private final NamedParameterJdbcTemplate jdbcTemplate;

public RestaurantDao(DataSource dataSource) {
this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}

public long createRestaurant(PostRestaurantRequest postRestaurantRequest) {
String sql = "insert into restaurant(address, category, latitude, longitude, min_price, name, star, picture_url) " +
"values(:address, :category, :latitude, :longitude, :min_price, :name, :star, :picture_url)";

SqlParameterSource param = new BeanPropertySqlParameterSource(postRestaurantRequest);
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(sql, param, keyHolder);

return Objects.requireNonNull(keyHolder.getKey()).longValue();
}

public List<GetRestaurantResponse> getRestaurants(double star, Long lastId) {
String sql = "SELECT id, name FROM restaurant WHERE star >= :star AND id > :lastId " +
"ORDER BY id LIMIT 10";

Map<String, Object> param = Map.of(
"star", star,
"lastId", lastId);

return jdbcTemplate.query(sql, param,
(rs, rowNum) -> new GetRestaurantResponse(
rs.getLong("id"),
rs.getString("name")));
}

}
18 changes: 9 additions & 9 deletions src/main/java/kuit3/backend/dao/UserDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,38 +68,38 @@ public List<GetUserResponse> getUsers(String nickname, String email, String stat
}

public long getUserIdByEmail(String email) {
String sql = "select user_id from user where email=:email and status='active'";
String sql = "select id from user where email=:email and status='active'";
Map<String, Object> param = Map.of("email", email);
return jdbcTemplate.queryForObject(sql, param, long.class);
}

public String getPasswordByUserId(long userId) {
String sql = "select password from user where user_id=:user_id and status='active'";
Map<String, Object> param = Map.of("user_id", userId);
String sql = "select password from user where id=:id and status='active'";
Map<String, Object> param = Map.of("id", userId);
return jdbcTemplate.queryForObject(sql, param, String.class);
}

public int modifyUserStatus_dormant(long userId) {
String sql = "update user set status=:status where user_id=:user_id";
String sql = "update user set status=:status where id=:id";
Map<String, Object> param = Map.of(
"status", "dormant",
"user_id", userId);
"id", userId);
return jdbcTemplate.update(sql, param);
}

public int modifyUserStatus_deleted(long userId) {
String sql = "update user set status=:status where user_id=:user_id";
String sql = "update user set status=:status where id=:id";
Map<String, Object> param = Map.of(
"status", "deleted",
"user_id", userId);
"id", userId);
return jdbcTemplate.update(sql, param);
}

public int modifyNickname(long userId, String nickname) {
String sql = "update user set nickname=:nickname where user_id=:user_id";
String sql = "update user set nickname=:nickname where id=:id";
Map<String, Object> param = Map.of(
"nickname", nickname,
"user_id", userId);
"id", userId);
return jdbcTemplate.update(sql, param);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package kuit3.backend.dto.restaurant;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class GetRestaurantResponse {

private Long id;
private String name;

}
Loading