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

로그인 만들기 #75

Merged
merged 44 commits into from Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
65ebd1b
feat: (common) Mapstruct 의존성 추가
giibeom Nov 15, 2022
2f8740f
refactor: (common) 도메인 별로 패키지 분리
giibeom Nov 15, 2022
97afaf6
refactor: (common) 도메인 별 예외 핸들링 분리
giibeom Nov 15, 2022
fa8fe31
feat: (common) Jackson 라이브러리를 통한 JsonUtil
giibeom Nov 15, 2022
a9e167d
feat: (common) MockMvc 테스트 결과 값의 CharacterEncoding을 UTF-8로 설정
giibeom Nov 15, 2022
6531d5c
test: (session-presentation) 로그인 성공 시 201 코드 반환 케이스
giibeom Nov 15, 2022
26cfd82
feat: (session-presentation) 로그인 API
giibeom Nov 15, 2022
3fbca85
test: (session-application) 로그인 성공 시 토큰 반환 케이스
giibeom Nov 15, 2022
869b9ce
merge: [Day-2] 도메인 별 패키지 분리, 로그인 API 기능 구현중
giibeom Nov 15, 2022
15b58c0
test: (session-presentation) Controller 내부 구현 mock 설정 (authentication…
giibeom Nov 16, 2022
986939b
feat: (session-application) 로그인 시 유저의 id를 인코딩 한 jwt 토큰을 반환
giibeom Nov 16, 2022
144bd16
test: (session-application) 유효한 회원 정보가 주어지면 해당 id로 인코딩 된 토큰 반환 케이스
giibeom Nov 16, 2022
100af53
test: (common) JwtUtil id로 토큰 인코딩 성공 케이스
giibeom Nov 16, 2022
75a144e
feat: (common) JwtUtil id를 사용한 토큰 인코딩
giibeom Nov 16, 2022
5a1d34a
refactor: mock 테스트의 행위 검증(verify) 추가 및 given 절 메서드 분리
giibeom Nov 16, 2022
30420ca
merge: [Day-3] jwt 토큰 인코딩 구현, mock 테스트 연습
giibeom Nov 16, 2022
66ff673
refactor: 전체 구조 도메인 형으로 변경, HelloController 삭제
giibeom Nov 16, 2022
bbe5eb3
test: (session-presentation) 로그인 시 요청 데이터 유효성 검사 실패 케이스 (이메일, 비밀번호)
giibeom Nov 17, 2022
dd99412
feat: (session-presentation) 로그인 시 요청 데이터 유효성 검사 (이메일, 비밀번호)
giibeom Nov 17, 2022
5745766
test: (session-presentation) 로그인 시 가입된 회원이 아닌 경우의 예외 케이스
giibeom Nov 17, 2022
2e8a930
feat: (session-presentation) 로그인 시 가입된 회원이 아닌 경우 404 응답 코드 반환
giibeom Nov 17, 2022
5417764
test: (session-presentation) 로그인 시 비밀번호가 틀린 경우의 예외 케이스
giibeom Nov 17, 2022
2643caf
feat: (session-presentation) 로그인 시 비밀번호가 틀린 경우 403 응답 코드 반환
giibeom Nov 17, 2022
0260115
test: (session-application) 로그인 시 찾을 수 없는 계정일 경우의 예외 케이스
giibeom Nov 17, 2022
f882811
feat: (session-application) 로그인 시 해당 계정이 없다면 예외 발생 (UserNotFoundExcep…
giibeom Nov 17, 2022
254787c
test: (session-application) 로그인 시 비밀번호가 틀린 경우의 예외 케이스
giibeom Nov 17, 2022
8dc5d21
feat: (session-application) 로그인 시 비밀번호가 틀렸다면 예외 발생 (UserInvalidPasswo…
giibeom Nov 17, 2022
5742528
test: (common-util) 디코딩 할 토큰이 유효할 경우 userId가 포함된 클레임 반환 케이스
giibeom Nov 17, 2022
9741fdd
feat: (common-jwtUtil) secretKey를 사용한 토큰 디코딩
giibeom Nov 17, 2022
29389dd
test: (common-jwtUtil) 토큰이 유효하지 않거나 공백인 예외 케이스
giibeom Nov 17, 2022
2d9eea1
feat: (common-jwtUtil) 토큰이 유효하지 않거나 공백이면 예외 발생 (InvalidTokenException)
giibeom Nov 17, 2022
1184c6e
merge: [Day-4] 토큰 인코딩, 디코딩 구현 및 테스트 완료
giibeom Nov 17, 2022
863f8a0
fix: (session-application) 로그인 시 찾을 수 없는 계정인 예외 케이스에서 mocking 반환 값 수정
giibeom Nov 17, 2022
db0ca44
fix: (common-jwtUtil) secretKey를 기존 값으로 변경하여 토큰 fixture 데이터의 인코딩 디코딩 …
giibeom Nov 17, 2022
4235ee9
feat: (common-interceptor) 로그인이 필요한 handler로 API 요청이 올 때 Auth 토큰 검증
giibeom Nov 18, 2022
492feee
test: (common-jwtUtil) accessToken 검증 시 토큰이 유효하지 않은 3개의 예외 케이스
giibeom Nov 18, 2022
98f56bb
test: (common-interceptor) 로그인이 필요한 API 요청 시 Auth 토큰이 없는 예외 케이스
giibeom Nov 18, 2022
069a3b8
feat: (common-interceptor) 로그인이 필요한 API에 `@Login`을 선언하여 Auth 토큰 검증
giibeom Nov 18, 2022
cd65f7a
merge: [Day-5] Interceptor를 통해 인증이 필요한 API인 경우 Auth Token 검증
giibeom Nov 18, 2022
d16fb31
refactor: 패키지 구조 변경 (exception)
giibeom Nov 19, 2022
25cfbec
fix: 로그인이 필요한 Controller 테스트에 Auth 토큰 헤더 추가
giibeom Nov 19, 2022
03d00fc
refactor: `@Login` 어노테이션을 `@LoginRequired`로 변경
giibeom Nov 19, 2022
7c93654
merge: [Day-6] 예외 객체 패키지 구조 변경, 로그인 인증 어노테이션 변경
giibeom Nov 19, 2022
48399f6
refactor: error 패키지 및 객체 모두 exception으로 변경
giibeom Nov 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,57 @@
package com.codesoom.assignment.common.auth;

import com.codesoom.assignment.common.util.JwtUtil;
import com.codesoom.assignment.domain.session.exception.TokenNotExistException;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

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

@Component
public class AuthenticationInterceptor implements HandlerInterceptor {

private final JwtUtil jwtUtil;

public AuthenticationInterceptor(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}

@Override
public boolean preHandle(final HttpServletRequest request,
final HttpServletResponse response,
final Object handler) throws Exception {
if (isNotHandlerMethod(handler) || isNotRequiredAuth(handler)) {
return true;
}

if (isNotExistAuthorization(request)) {
throw new TokenNotExistException();
}

validateAuthToken(request);

return true;
}

private void validateAuthToken(HttpServletRequest request) {
jwtUtil.validateAccessToken(request.getHeader(HttpHeaders.AUTHORIZATION));
}

private static boolean isNotExistAuthorization(HttpServletRequest request) {
return request.getHeader(HttpHeaders.AUTHORIZATION) == null;
}

private static boolean isNotHandlerMethod(Object handler) {
return !(handler instanceof HandlerMethod);
}

private boolean isNotRequiredAuth(Object handler) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Login auth = handlerMethod.getMethodAnnotation(Login.class);

return auth == null || !auth.required();
}
}
13 changes: 13 additions & 0 deletions app/src/main/java/com/codesoom/assignment/common/auth/Login.java
@@ -0,0 +1,13 @@
package com.codesoom.assignment.common.auth;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Login {
giibeom marked this conversation as resolved.
Show resolved Hide resolved

boolean required() default true;
}
@@ -0,0 +1,25 @@
package com.codesoom.assignment.common.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

private final List<HandlerInterceptor> interceptors;

public WebConfig(List<HandlerInterceptor> interceptors) {
this.interceptors = interceptors;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
for (HandlerInterceptor interceptor : interceptors) {
registry.addInterceptor(interceptor);
}
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/codesoom/assignment/common/util/JwtUtil.java
@@ -1,6 +1,7 @@
package com.codesoom.assignment.common.util;

import com.codesoom.assignment.domain.session.exception.InvalidTokenException;
import com.codesoom.assignment.domain.session.exception.TokenNotExistException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
Expand All @@ -12,6 +13,7 @@

@Component
public class JwtUtil {
private static final String ACCESS_TOKEN_TYPE = "Bearer";
private final Key secretKey;

public JwtUtil(@Value("${jwt.secret}") String secretKey) {
Expand Down Expand Up @@ -40,4 +42,16 @@ public Claims decode(String token) {
throw new InvalidTokenException(token);
}
}

public void validateAccessToken(String authHeader) {
if (authHeader == null) {
throw new TokenNotExistException();
}

if (!authHeader.startsWith(ACCESS_TOKEN_TYPE)) {
throw new InvalidTokenException();
}

decode(authHeader.substring(ACCESS_TOKEN_TYPE.length()));
}
}
@@ -1,6 +1,10 @@
package com.codesoom.assignment.domain.session.exception;

public class InvalidTokenException extends RuntimeException{
public class InvalidTokenException extends RuntimeException {
public InvalidTokenException() {
super("토큰이 유효하지 않습니다");
}

public InvalidTokenException(String token) {
super("토큰이 유효하지 않습니다: " + token);
}
Expand Down
@@ -0,0 +1,7 @@
package com.codesoom.assignment.domain.session.exception;

public class TokenNotExistException extends RuntimeException {
public TokenNotExistException() {
super("토큰이 존재하지 않습니다");
}
}