Skip to content

Commit

Permalink
Merge branch 'develop' into feature/74
Browse files Browse the repository at this point in the history
  • Loading branch information
hanyMK committed Nov 17, 2023
2 parents dee5682 + 11f8e1c commit 59c80cc
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
@Repository
public interface AnimeRepository extends JpaRepository<Anime,Long>, AnimeRepositoryCustom {

@Query("select a from Anime a where a.id = :id")
@Query("select a from Anime a where a.id = :id and a.deletedAt is null")
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="3000")})
Optional<Anime> findByIdForUpdate(@Param("id")Long id);

@Query("select a from Anime a where a.id = :id and a.deletedAt = null and a.isReleased = :isReleased")
Optional<Anime> findAnimeByConditions(@Param("id") Long id, @Param("isReleased") boolean isReleased);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public boolean createScore(Long memberId, Long animeId, int score) {
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new NotFoundException("Member"));

Anime anime = animeRepository.findById(animeId)
Anime anime = animeRepository.findByIdForUpdate(animeId)
.orElseThrow(() -> new NotFoundException("Anime"));

anime.increaseStarRatingScore(score);
Expand All @@ -60,15 +60,24 @@ public RatedRes checkRated(Long memberId, Long animeId) {
}

@Override
@Transactional
public boolean updateScore(Long memberId, Long animeId, int score) {
StarRating foundStarRating = findByMemberIdAndAnimeId(memberId, animeId)
.orElseThrow(() -> new NotFoundException("StarRating"));

if (foundStarRating.getScore() == score) {
int prevScore = foundStarRating.getScore();

Anime anime = animeRepository.findByIdForUpdate(animeId)
.orElseThrow(() -> new NotFoundException("Anime"));

if (prevScore == score) {
return false;
}

anime.decreaseStarRatingScore(prevScore);

foundStarRating.updateScore(score);
anime.increaseStarRatingScore(score);

starRatingRepository.save(foundStarRating);
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import static org.springframework.security.config.Customizer.withDefaults;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.oduck.api.domain.member.entity.Role;
//import io.oduck.api.global.security.filter.LocalAuthenticationFilter;
import io.oduck.api.global.security.filter.HTTPLoggingFilter;
import io.oduck.api.global.security.handler.ForbiddenHandler;
import io.oduck.api.global.security.handler.LoginFailureHandler;
import io.oduck.api.global.security.handler.LoginSuccessHandler;
Expand All @@ -24,6 +24,7 @@
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
//import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
//import org.springframework.security.web.context.SecurityContextRepository;
Expand All @@ -34,13 +35,14 @@
@Configuration
public class SecurityConfig {

// private final ObjectMapper objectMapper;
// private final ObjectMapper objectMapper;
private final LogoutHandler logoutHandler;
private final SocialLoginService socialLoginService;
private final LoginSuccessHandler loginSuccessHandler;
private final LoginFailureHandler loginFailureHandler;
private final ForbiddenHandler forbiddenHandler;
private final UnauthorizedHandler unauthorizedHandler;
private final HTTPLoggingFilter HTTPLoggingFilter;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
Expand Down Expand Up @@ -75,15 +77,17 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// 인가 설정
http
.authorizeHttpRequests((authorizeRequests) ->
authorizeRequests
// .requestMatchers("docs/index.html").hasAuthority(Role.ADMIN.name())
.requestMatchers("/auth/status").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
.requestMatchers(HttpMethod.PUT, "/members/**").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
.requestMatchers(HttpMethod.PATCH, "/members/**").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
.requestMatchers(HttpMethod.DELETE, "/members/**").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
.requestMatchers( "/bookmarks/**").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
authorizeRequests
// .requestMatchers("docs/index.html").hasAuthority(Role.ADMIN.name())
.requestMatchers("/auth/status").hasAnyAuthority(Role.WITHDRAWAL.name(), Role.MEMBER.name(), Role.ADMIN.name())
.requestMatchers(HttpMethod.PUT, "/members/**").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
.requestMatchers(HttpMethod.PATCH, "/members/**").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
.requestMatchers(HttpMethod.DELETE, "/members/**").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
.requestMatchers(HttpMethod.POST, "/bookmarks/**").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
.requestMatchers(HttpMethod.POST, "/ratings/**").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
.requestMatchers(HttpMethod.PATCH, "/ratings/**").hasAnyAuthority(Role.MEMBER.name(), Role.ADMIN.name())
// .requestMatchers("/oduckdmin/**").hasAuthority(Role.ADMIN.name())
.anyRequest().permitAll()
.anyRequest().permitAll()
);

// 로그아웃 설정
Expand All @@ -104,12 +108,12 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.oauth2Login((oauth2Login) ->
oauth2Login
.userInfoEndpoint((userInfoEndpoint) ->
userInfoEndpoint
.userService(socialLoginService)
)
.successHandler(loginSuccessHandler)
.failureHandler(loginFailureHandler)
.userInfoEndpoint((userInfoEndpoint) ->
userInfoEndpoint
.userService(socialLoginService)
)
.successHandler(loginSuccessHandler)
.failureHandler(loginFailureHandler)
);

// 예외 처리 설정
Expand All @@ -121,6 +125,9 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.accessDeniedHandler(forbiddenHandler)
);

http
.addFilterBefore(HTTPLoggingFilter, LogoutFilter.class);

return http.build();
}

Expand All @@ -142,10 +149,10 @@ public AuthenticationManager authenticationManager(

// // Custom Configurer : CustomFilterConfigurer 는 직접 구현한 필터인 JwtAuthenticationFilter 를 등록하는 역할
// public class CustomFilterConfigurer extends AbstractHttpConfigurer<CustomFilterConfigurer, HttpSecurity> {
// AbstractHttpConfigurer 를 상속하여 구현
// AbstractHttpConfigurer<AbstractHttpConfigurer 를 상속하는 타입, HttpSecurityBuilder 를 상속하는 타입> 을 지정
// AbstractHttpConfigurer 를 상속하여 구현
// AbstractHttpConfigurer<AbstractHttpConfigurer 를 상속하는 타입, HttpSecurityBuilder 를 상속하는 타입> 을 지정

// configure() 메서드를 오버라이드해서 Configuration 을 커스터마이징
// configure() 메서드를 오버라이드해서 Configuration 을 커스터마이징
// @Override
// public void configure(HttpSecurity builder) throws Exception {
//
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.oduck.api.global.security.filter;

import static io.oduck.api.global.utils.HttpHeaderUtils.getClientIP;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

@Slf4j
@Component
public class HTTPLoggingFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {

if (isAsyncDispatch(request)) {
filterChain.doFilter(request, response);
} else {
doFilterWrapped(new ContentCachingRequestWrapper(request),
new ContentCachingResponseWrapper(response), filterChain);
}
}

protected void doFilterWrapped(ContentCachingRequestWrapper request,
ContentCachingResponseWrapper response,
FilterChain filterChain) throws IOException, ServletException {
try {
filterChain.doFilter(request, response);
logRequest(request);
} finally {
logResponse(response);
response.copyBodyToResponse();
}
}

private static void logRequest(ContentCachingRequestWrapper request) throws IOException {
String queryString = request.getQueryString();
log.info("Request : \n {} uri=[{}]\n content-type[{}]\n client-ip[{}]\n user-agent[{}]", request.getMethod(),
queryString == null ? request.getRequestURI() : request.getRequestURI() + queryString,
request.getContentType(), getClientIP(request), request.getHeader("User-Agent"));
logPayload("Request", request.getContentType(), request.getContentAsByteArray());
}

private static void logResponse(ContentCachingResponseWrapper response) throws IOException {
logPayload("Response", response.getContentType(), response.getContentAsByteArray());
}

private static void logPayload(String prefix, String contentType, byte[] rowData)
throws IOException {
boolean visible = isVisible(
MediaType.valueOf(contentType == null ? "application/json" : contentType));

if (visible) {
if (rowData.length > 0) {
String contentString = new String(rowData);
log.info("{}\n Payload: {}", prefix, contentString);
}
} else {
log.info("{} Payload: Binary Content", prefix);
}
}

private static boolean isVisible(MediaType mediaType) {
final List<MediaType> VISIBLE_TYPES = Arrays.asList(
MediaType.valueOf("text/*"),
MediaType.APPLICATION_FORM_URLENCODED,
MediaType.APPLICATION_JSON,
MediaType.APPLICATION_XML,
MediaType.valueOf("application/*+json"),
MediaType.valueOf("application/*+xml"),
MediaType.MULTIPART_FORM_DATA
);

return VISIBLE_TYPES.stream()
.anyMatch(visibleType -> visibleType.includes(mediaType));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void createScore() {
.willReturn(Optional.empty());
given(memberRepository.findById(memberId))
.willReturn(Optional.ofNullable(member));
given(animeRepository.findById(animeId))
given(animeRepository.findByIdForUpdate(animeId))
.willReturn(Optional.ofNullable(anime));

// when
Expand Down Expand Up @@ -173,6 +173,8 @@ void updateScore() {

given(starRatingRepository.findByMemberIdAndAnimeId(memberId, animeId))
.willReturn(Optional.ofNullable(starRating));
given(animeRepository.findByIdForUpdate(animeId))
.willReturn(Optional.ofNullable(anime));

// when
boolean result = starRatingService.updateScore(memberId, animeId, 5);
Expand All @@ -194,6 +196,8 @@ void updateScoreIfNotExist() {

given(starRatingRepository.findByMemberIdAndAnimeId(memberId, animeId))
.willReturn(Optional.ofNullable(starRating));
given(animeRepository.findByIdForUpdate(animeId))
.willReturn(Optional.ofNullable(anime));

// when
boolean result = starRatingService.updateScore(memberId, animeId, score);
Expand Down

0 comments on commit 59c80cc

Please sign in to comment.