Skip to content

Commit

Permalink
Feature/74: isScrap 필드 추가 (#77)
Browse files Browse the repository at this point in the history
* ✨ Feat: scrapId를 내려주기 위한 세팅

AuthUserArgumentResolver 멤버 추출 로직 변경, SecurityConfig HttpSecurity 설정, BriefingDetailDTO 필드추가

* ♻️ Refactor: 불필요한 출력문 제거

* ✨ Feat: isScrap 필드 내려주기

로그인 한 사용자 (true/false), 로그인 안 한 사용자(false)
  • Loading branch information
swa07016 authored Oct 14, 2023
1 parent ce2e769 commit 1adbd27
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 21 deletions.
17 changes: 15 additions & 2 deletions src/main/java/briefing/briefing/api/BriefingApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@
import briefing.briefing.application.dto.*;
import briefing.briefing.domain.BriefingType;
import java.time.LocalDate;
import java.util.Optional;

import briefing.common.response.CommonResponse;
import briefing.member.domain.Member;
import briefing.scrap.application.ScrapQueryService;
import briefing.security.handler.annotation.AuthMember;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand All @@ -27,6 +33,7 @@ public class BriefingApi {

private final BriefingQueryService briefingQueryService;
private final BriefingCommandService briefingCommandService;
private final ScrapQueryService scrapQueryService;

@GetMapping
public CommonResponse<BriefingResponseDTO.BriefingPreviewListDTO> findBriefings(
Expand All @@ -37,8 +44,14 @@ public CommonResponse<BriefingResponseDTO.BriefingPreviewListDTO> findBriefings(
}

@GetMapping("/{id}")
public CommonResponse<BriefingResponseDTO.BriefingDetailDTO> findBriefing(@PathVariable final Long id) {
return CommonResponse.onSuccess(BriefingConverter.toBriefingDetailDTO(briefingQueryService.findBriefing(id)));
@Parameter(name = "member", hidden = true)
public CommonResponse<BriefingResponseDTO.BriefingDetailDTO> findBriefing(@PathVariable final Long id, @AuthMember Member member) {

Boolean isScrap = Optional.ofNullable(member)
.map(m -> scrapQueryService.existsByMemberIdAndBriefingId(m.getId(), id))
.orElseGet(() -> Boolean.FALSE);

return CommonResponse.onSuccess(BriefingConverter.toBriefingDetailDTO(briefingQueryService.findBriefing(id), isScrap));
}

@PostMapping
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/briefing/briefing/api/BriefingConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static BriefingResponseDTO.ArticleResponseDTO toArticleResponseDTO(final
.build();
}

public static BriefingResponseDTO.BriefingDetailDTO toBriefingDetailDTO(Briefing briefing){
public static BriefingResponseDTO.BriefingDetailDTO toBriefingDetailDTO(Briefing briefing, Boolean isScrap){

List<BriefingResponseDTO.ArticleResponseDTO> articleResponseDTOList = briefing.getBriefingArticles().stream()
.map(article -> toArticleResponseDTO(article.getArticle())).toList();
Expand All @@ -54,6 +54,7 @@ public static BriefingResponseDTO.BriefingDetailDTO toBriefingDetailDTO(Briefing
.content(briefing.getContent())
.date(briefing.getCreatedAt().toLocalDate())
.articles(articleResponseDTOList)
.isScrap(isScrap)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public static class BriefingDetailDTO{
String content;
LocalDate date;
List<ArticleResponseDTO> articles;
Boolean isScrap;
}

@Builder
Expand Down
2 changes: 0 additions & 2 deletions src/main/java/briefing/member/api/MemberApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.sql.Ref;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

@Tag(name = "02-Member \uD83D\uDC64",description = "사용자 관련 API")
@RestController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@ public class ScrapQueryService {
public List<Scrap> getScrapsByMemberId(Long memberId) {
return scrapRepository.findByMember_Id(memberId);
}


public Boolean existsByMemberIdAndBriefingId(Long memberId, Long briefingId) {
return scrapRepository.existsByMember_IdAndBriefing_Id(memberId, briefingId);
}
}
7 changes: 3 additions & 4 deletions src/main/java/briefing/security/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.sessionManagement(manage -> manage.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // Session 사용 안함
.formLogin(AbstractHttpConfigurer::disable) // form login 사용 안함
.httpBasic(AbstractHttpConfigurer::disable) // http basic 방식 사용 안함
// .authorizeHttpRequests(authorize -> authorize // lambda 방식
// //.requestMatchers(WHITE_LIST).permitAll()
// .anyRequest().authenticated()
// )
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/briefings/**").permitAll() // 모두 접근 가능합니다.
)
.exceptionHandling(exceptionHandling -> exceptionHandling
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(jwtAccessDeniedHandler)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class JwtRequestFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest httpServletRequest = request;
String jwt = tokenProvider.resolveToken(httpServletRequest);

if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt, TokenProvider.TokenType.ACCESS)){

Authentication authentication = tokenProvider.getAuthentication(jwt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
import briefing.member.api.MemberConverter;
import briefing.member.application.MemberQueryService;
import briefing.member.domain.Member;
import briefing.security.provider.TokenProvider;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
Expand All @@ -22,6 +25,7 @@ public class AuthUserArgumentResolver implements HandlerMethodArgumentResolver {


private final MemberQueryService memberQueryService;
private final TokenProvider tokenProvider;

@Override
public boolean supportsParameter(MethodParameter parameter) {
Expand All @@ -33,20 +37,24 @@ public boolean supportsParameter(MethodParameter parameter) {
return true;
}


/*
NOTE - 사용자 추출 방법 변경
기존) 스프링 시큐리티 컨텍스트에서 유저정보를 가져와 세팅해주었습니다.
현재) httpRequest의 authorization header에서 액세스 토큰을 가져와 사용자 정보를 반환합니다.
변경 배경)
permitAll()을 통해 인증 유무에 상관없이 제공되는 API에서 JwtRequestFilter까지 도달하지 않는 문제인해
authentication 객체가 세팅이 되지 않기 때문에 기존 방법으로는 토큰을 물고 있는 사용자라도 AuthMember를 통해 추출하면 null이 반환되었습니다.
*/
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Object principal = null;
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

if (authentication != null) {
principal = authentication.getPrincipal();
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
String jwt = tokenProvider.resolveToken(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt, TokenProvider.TokenType.ACCESS)) {
// 토큰에서 사용자 ID (subject) 추출
String userId = tokenProvider.getAuthentication(jwt).getName();
return memberQueryService.findById(Long.valueOf(userId));
}
if (principal == null || principal.getClass() == String.class) {
throw new MemberException(ErrorCode.MEMBER_NOT_FOUND);
}

UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) authentication;
Member member = memberQueryService.findById(Long.valueOf(authenticationToken.getName()));
return member;
return null; // 토큰이 없거나 유효하지 않은 경우
}
}

0 comments on commit 1adbd27

Please sign in to comment.