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

3단계 - 즐겨찾기 기능 구현 #355

Open
wants to merge 29 commits into
base: hscom96
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b199287
feat: 1단계 초기화
Aug 15, 2022
7730e74
feat: 권한 enum 추가
Aug 15, 2022
bf6f801
refactor: 메서드 위치 변경
Aug 15, 2022
0ebcbd6
feat: custom exception 추가
Aug 16, 2022
ea1eca3
fix: 테스트 오류 수정
Sep 4, 2022
dcb9838
refactor: XXXAuthenticationFilter의 구조화
Sep 5, 2022
8109ffa
refactor: auth 패키지와 member 패키지에 대한 의존 제거
Sep 5, 2022
73ba170
refactor: UserDetail 의존성 역전
Sep 5, 2022
3d45966
refactor: AuthNotChainInterceptor 메서드 구조화
Sep 5, 2022
9570e2b
refactor: AuthChainInterceptor 메서드 구조화
Sep 5, 2022
4aa8fb1
style: 클래스명 UserDetailService 변경
Sep 6, 2022
6ed9daf
Merge branch 'hscom96' into step2
Sep 7, 2022
18e19c0
refactor: given() 메서드 간소화
Sep 7, 2022
797aff7
feat: @Overide 태그 추가
Sep 12, 2022
1859e9b
style: userdetailservice 변수명 변경
Sep 12, 2022
6b73538
style: 클래스명 변경 및 메서드명 통일
Sep 12, 2022
b794805
refactor: AuthenticationPrincipalArgumentResolver 클래스 member 패키지 의존성 제거
Sep 14, 2022
91d8c97
feat: 인수테스트 작성
Sep 26, 2022
05305bc
feat: 즐겨찾기 등록 controller 구현
Sep 26, 2022
2d746dd
feat: 즐겨찾기 도메인 구현
Sep 27, 2022
0c419ad
feat: 즐겨찾기 등록 service 구현
Sep 27, 2022
a8d4b2a
feat: 즐겨찾기 조회 구현
Sep 29, 2022
fefa7ed
feat: 즐겨찾기 삭제 구현
Sep 29, 2022
d9c8b9b
merge commit
Sep 29, 2022
49171fe
merge commit
Sep 29, 2022
d1b97b5
feat: 트랜잭션 추가
Oct 1, 2022
33bc833
feat: 예외클래스 구체화
Oct 1, 2022
e194e54
test: 유효하지 않은 사용자 예외 케이스 검증 추가
Oct 13, 2022
0e880a2
feat: UserDetail 인터페이스 생성 및 User 객체 추상화
Oct 13, 2022
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
8 changes: 4 additions & 4 deletions src/main/java/nextstep/auth/AuthConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
@RequiredArgsConstructor
@Configuration
public class AuthConfig implements WebMvcConfigurer {
private final UserDetailService loginMemberService;
private final UserDetailService userDetailService;
hscom96 marked this conversation as resolved.
Show resolved Hide resolved
private final JwtTokenProvider jwtTokenProvider;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SecurityContextPersistenceFilter());
registry.addInterceptor(new UsernamePasswordAuthFilter(loginMemberService)).addPathPatterns("/login/form");
registry.addInterceptor(new TokenAuthInterceptor(loginMemberService, jwtTokenProvider)).addPathPatterns("/login/token");
registry.addInterceptor(new BasicAuthFilter(loginMemberService));
registry.addInterceptor(new UsernamePasswordAuthFilter(userDetailService)).addPathPatterns("/login/form");
registry.addInterceptor(new TokenAuthInterceptor(userDetailService, jwtTokenProvider)).addPathPatterns("/login/token");
registry.addInterceptor(new BasicAuthFilter(userDetailService));
registry.addInterceptor(new BearerTokenAuthFilter(jwtTokenProvider));
}

Expand Down
12 changes: 7 additions & 5 deletions src/main/java/nextstep/auth/authentication/BasicAuthFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@

import lombok.RequiredArgsConstructor;
import nextstep.auth.context.Authentication;
import nextstep.auth.context.SecurityContextHolder;
import nextstep.auth.user.User;
import nextstep.auth.user.UserDetail;
import nextstep.auth.user.UserDetailService;
import nextstep.auth.interceptor.AuthChainInterceptor;
import nextstep.auth.interceptor.AuthContextChainInterceptor;
import org.apache.tomcat.util.codec.binary.Base64;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RequiredArgsConstructor
public class BasicAuthFilter extends AuthChainInterceptor {
public class BasicAuthFilter extends AuthContextChainInterceptor {
private final UserDetailService userDetailService;

@Override
protected void checkValidAuth(final AuthenticationToken token) {
UserDetail loginMember = userDetailService.loadUserByUsername(token.getPrincipal());
if (loginMember == null) {
Expand All @@ -25,12 +25,14 @@ protected void checkValidAuth(final AuthenticationToken token) {
}
}

@Override
protected Authentication getAuthentication(final AuthenticationToken token) {
UserDetail loginMember = userDetailService.loadUserByUsername(token.getPrincipal());
return new Authentication(loginMember.getEmail(), loginMember.getAuthorities());
}

protected AuthenticationToken getAuthenticationToken(final HttpServletRequest request) {
@Override
protected AuthenticationToken createAuthToken(final HttpServletRequest request) {
String authCredentials = AuthorizationExtractor.extract(request, AuthorizationType.BASIC);
String authHeader = new String(Base64.decodeBase64(authCredentials));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@
import lombok.RequiredArgsConstructor;
import nextstep.auth.context.Authentication;
import nextstep.auth.token.JwtTokenProvider;
import nextstep.auth.interceptor.AuthChainInterceptor;
import nextstep.auth.interceptor.AuthContextChainInterceptor;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@RequiredArgsConstructor
public class BearerTokenAuthFilter extends AuthChainInterceptor {
public class BearerTokenAuthFilter extends AuthContextChainInterceptor {
private final JwtTokenProvider jwtTokenProvider;

@Override
protected void checkValidAuth(final AuthenticationToken token) {
if (!jwtTokenProvider.validateToken(token.getPrincipal())) {
throw new AuthenticationException();
}
}

@Override
protected Authentication getAuthentication(final AuthenticationToken token) {
String principal = jwtTokenProvider.getPrincipal(token.getPrincipal());
List<String> roles = jwtTokenProvider.getRoles(token.getPrincipal());
Expand All @@ -26,7 +28,8 @@ protected Authentication getAuthentication(final AuthenticationToken token) {
return authentication;
}

protected AuthenticationToken getAuthenticationToken(final HttpServletRequest request) {
@Override
protected AuthenticationToken createAuthToken(final HttpServletRequest request) {
String authCredentials = AuthorizationExtractor.extract(request, AuthorizationType.BEARER);
return new AuthenticationToken(authCredentials, authCredentials);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import nextstep.auth.context.Authentication;
import nextstep.auth.context.SecurityContextHolder;
import nextstep.auth.user.UserDetail;
import nextstep.auth.interceptor.AuthNotChainInterceptor;
import nextstep.auth.user.User;
import nextstep.auth.user.UserDetail;
import nextstep.auth.user.UserDetailService;

import javax.servlet.http.HttpServletRequest;
Expand All @@ -27,8 +28,8 @@ protected AuthenticationToken createAuthToken(final HttpServletRequest request)
}

@Override
protected void afterSuccessUserCheck(final HttpServletRequest request, final HttpServletResponse response, UserDetail userDetail) {
Authentication authentication = new Authentication(userDetail.getEmail(), userDetail.getAuthorities());
protected void afterSuccessUserCheck(final HttpServletRequest request, final HttpServletResponse response, UserDetail user) {
Authentication authentication = new Authentication(user.getEmail(), user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import nextstep.auth.context.Authentication;
import nextstep.auth.context.SecurityContextHolder;
import nextstep.member.domain.LoginMember;
import nextstep.auth.user.User;
hscom96 marked this conversation as resolved.
Show resolved Hide resolved
import nextstep.auth.user.UserDetail;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
Expand All @@ -16,12 +17,12 @@ public boolean supportsParameter(MethodParameter parameter) {
}

@Override
public LoginMember resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
public UserDetail resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
return LoginMember.guest();
return User.guest();
}

return LoginMember.of(authentication.getPrincipal().toString(), authentication.getAuthorities());
return User.of(authentication.getPrincipal().toString(), authentication.getAuthorities());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public abstract class AuthChainInterceptor implements HandlerInterceptor {
public abstract class AuthContextChainInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler){
try {
AuthenticationToken token = getAuthenticationToken(request);
AuthenticationToken token = createAuthToken(request);
checkValidAuth(token);
saveAuthContext(token);
return true;
Expand All @@ -26,7 +26,7 @@ public boolean preHandle(final HttpServletRequest request, final HttpServletResp

protected abstract Authentication getAuthentication(final AuthenticationToken token);

protected abstract AuthenticationToken getAuthenticationToken(final HttpServletRequest request);
protected abstract AuthenticationToken createAuthToken(final HttpServletRequest request);

private void saveAuthContext(final AuthenticationToken token) {
Authentication authentication = getAuthentication(token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lombok.RequiredArgsConstructor;
import nextstep.auth.authentication.AuthenticationException;
import nextstep.auth.authentication.AuthenticationToken;
import nextstep.auth.user.User;
import nextstep.auth.user.UserDetail;
import nextstep.auth.user.UserDetailService;
import org.springframework.web.servlet.HandlerInterceptor;
Expand All @@ -19,9 +20,9 @@ public abstract class AuthNotChainInterceptor implements HandlerInterceptor {
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler){
try {
AuthenticationToken authToken = createAuthToken(request);
checkValidUser(authToken);
UserDetail userDetail = getUserDetail(authToken);
afterSuccessUserCheck(request, response, userDetail);
checkValidAuth(authToken);
UserDetail user = getUserDetail(authToken);
afterSuccessUserCheck(request, response, user);
return false;
} catch (Exception e) {
return true;
Expand All @@ -30,10 +31,10 @@ public boolean preHandle(final HttpServletRequest request, final HttpServletResp

protected abstract AuthenticationToken createAuthToken(final HttpServletRequest request) throws IOException;

protected abstract void afterSuccessUserCheck(final HttpServletRequest request, final HttpServletResponse response, UserDetail userDetail)
protected abstract void afterSuccessUserCheck(final HttpServletRequest request, final HttpServletResponse response, UserDetail user)
throws IOException;

protected void checkValidUser(AuthenticationToken authToken){
protected void checkValidAuth(AuthenticationToken authToken){
UserDetail loginMember = getUserDetail(authToken);

if (loginMember == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import nextstep.auth.context.Authentication;
import nextstep.auth.context.SecurityContextHolder;
import nextstep.common.exception.CustomException;
import nextstep.common.exception.code.CommonCode;
import nextstep.common.exception.AuthException;
import nextstep.common.exception.code.AuthCode;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
Expand All @@ -27,11 +27,11 @@ public void checkAuthorities(JoinPoint joinPoint) {
List<String> values = Arrays.stream(secured.value()).map(Enum::name).collect(Collectors.toList());

Authentication authentication = Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
.orElseThrow(() -> new CustomException(CommonCode.AUTH_INVALID));
.orElseThrow(() -> new AuthException(AuthCode.AUTH_INVALID));

authentication.getAuthorities().stream()
.filter(values::contains)
.findFirst()
.orElseThrow(() -> new CustomException(CommonCode.AUTH_INVALID));
.orElseThrow(() -> new AuthException(AuthCode.AUTH_INVALID));
}
}
7 changes: 4 additions & 3 deletions src/main/java/nextstep/auth/token/TokenAuthInterceptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import nextstep.auth.authentication.AuthenticationToken;
import nextstep.auth.user.UserDetail;
import nextstep.auth.user.User;
import nextstep.auth.interceptor.AuthNotChainInterceptor;
import nextstep.auth.user.UserDetail;
import nextstep.auth.user.UserDetailService;
import org.springframework.http.MediaType;

Expand All @@ -30,8 +31,8 @@ protected AuthenticationToken createAuthToken(final HttpServletRequest request)
@Override
protected void afterSuccessUserCheck(final HttpServletRequest request,
final HttpServletResponse response,
final UserDetail userDetail) throws IOException {
String token = jwtTokenProvider.createToken(userDetail.getEmail(), userDetail.getAuthorities());
final UserDetail user) throws IOException {
String token = jwtTokenProvider.createToken(user.getEmail(), user.getAuthorities());
TokenResponse tokenResponse = new TokenResponse(token);

String responseToClient = new ObjectMapper().writeValueAsString(tokenResponse);
Expand Down
34 changes: 34 additions & 0 deletions src/main/java/nextstep/auth/user/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package nextstep.auth.user;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class User implements UserDetail{
private String email;
private String password;
private List<String> authorities;

public static User of(String email, List<String> authorities) {
return new User(email, null, authorities);
}

public static User of(String email, String password, List<String> authorities) {
return new User(email, password, authorities);
}

public static UserDetail guest() {
return new User();
}

@Override
public boolean checkPassword(final String password) {
return this.password.equals(password);
}
}
4 changes: 2 additions & 2 deletions src/main/java/nextstep/auth/user/UserDetail.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import java.util.List;

public interface UserDetail {
boolean checkPassword(final String password);

String getEmail();

String getPassword();

List<String> getAuthorities();

boolean checkPassword(String password);
}
2 changes: 1 addition & 1 deletion src/main/java/nextstep/common/CommonResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
public class CommonResponse<T> {
private int code;
private String message;
T data;
private T data;

public CommonResponse(ResponseCode responseCode) {
this.code = responseCode.getCode();
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/nextstep/common/exception/AuthException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package nextstep.common.exception;

import nextstep.common.exception.code.AuthCode;

public class AuthException extends CustomException{
public AuthException(final AuthCode authCode) {
super(authCode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import lombok.extern.slf4j.Slf4j;
import nextstep.common.CommonResponse;
import nextstep.common.exception.code.AuthCode;
import nextstep.common.exception.code.CommonCode;
import nextstep.common.exception.code.ResponseCode;
import org.springframework.dao.DataIntegrityViolationException;
Expand All @@ -28,6 +29,16 @@ public ResponseEntity<Object> handleCustomException(CustomException ex) {
return ResponseEntity.status(HttpStatus.OK).body(response);
}

/**
* 인증 exception 처리
*/
@ExceptionHandler(value = {AuthException.class})
public ResponseEntity<Object> handleAuthException(AuthException ex) {
ResponseCode responseCode = ex.getResponseCode();
CommonResponse<Object> response = new CommonResponse<>(responseCode);
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
}

/**
* 파라미터 유효성관련 exception 처리
*/
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/nextstep/common/exception/code/AuthCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package nextstep.common.exception.code;

import lombok.Getter;

@Getter
public enum AuthCode implements ResponseCode {
AUTH_INVALID(1002, "올바르지 않는 사용자입니다.");

private final int code;

private final String message;

AuthCode(int code, String message) {
this.code = code;
this.message = message;
}
}
3 changes: 1 addition & 2 deletions src/main/java/nextstep/common/exception/code/CommonCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
@Getter
public enum CommonCode implements ResponseCode {
ETC(1000, "알 수 없는 오류입니다."),
PARAM_INVALID(1001, "올바르지 않은 파라미터입니다."),
AUTH_INVALID(1002, "올바르지 않는 사용자입니다.");
PARAM_INVALID(1001, "올바르지 않은 파라미터입니다.");

private final int code;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package nextstep.member.application;

import nextstep.auth.user.User;
import nextstep.auth.user.UserDetail;
import nextstep.auth.user.UserDetailService;
import nextstep.member.domain.LoginMember;
import nextstep.member.domain.Member;
import nextstep.member.domain.MemberRepository;
import org.springframework.stereotype.Service;
Expand All @@ -14,8 +15,8 @@ public LoginMemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}

public LoginMember loadUserByUsername(String email) {
public UserDetail loadUserByUsername(String email) {
Member member = memberRepository.findByEmail(email).orElseThrow(RuntimeException::new);
return LoginMember.of(member);
return User.of(member.getEmail(), member.getPassword(), member.getRoles());
}
}
Loading