Skip to content

Commit

Permalink
REFACTOR(auth) :: security를 custom intercepter로 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
Woongbin06 committed Nov 8, 2024
1 parent ddf7e7e commit 44d18e6
Show file tree
Hide file tree
Showing 122 changed files with 794 additions and 800 deletions.
13 changes: 13 additions & 0 deletions src/main/java/com/woongeya/zoing/domain/annotation/AdminOnly.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.woongeya.zoing.domain.annotation;

import static java.lang.annotation.ElementType.*;

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

@Target(METHOD)
@Retention(RetentionPolicy.RUNTIME)
@LoginRequired
public @interface AdminOnly {
}
13 changes: 13 additions & 0 deletions src/main/java/com/woongeya/zoing/domain/annotation/LoginOrNot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.woongeya.zoing.domain.annotation;

import static java.lang.annotation.ElementType.*;

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


@Target({METHOD, ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginOrNot {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.woongeya.zoing.domain.annotation;

import static java.lang.annotation.ElementType.*;

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

@Target({METHOD, ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@LoginOrNot
public @interface LoginRequired {
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.woongeya.zoing.domain.application.exception;

import com.woongeya.zoing.global.error.exception.ErrorCode;
import com.woongeya.zoing.global.error.exception.ZoingException;
import com.woongeya.zoing.global.error.JJoingException;

public class AlreadyApplicationException extends ZoingException {
public class AlreadyApplicationException extends JJoingException {

public static final ZoingException EXCEPTION = new AlreadyApplicationException();
public static final JJoingException EXCEPTION = new AlreadyApplicationException();

public AlreadyApplicationException() {
super(ErrorCode.ALREADY_APPLICATION);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.woongeya.zoing.domain.application.exception;

import com.woongeya.zoing.global.error.exception.ErrorCode;
import com.woongeya.zoing.global.error.exception.ZoingException;
import com.woongeya.zoing.global.error.JJoingException;

public class ApplicationNotFoundException extends ZoingException {
public class ApplicationNotFoundException extends JJoingException {

public static final ZoingException EXCEPTION = new ApplicationNotFoundException();
public static final JJoingException EXCEPTION = new ApplicationNotFoundException();

public ApplicationNotFoundException () {
super(ErrorCode.APPLICATION_NOT_FOUND);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@
public class AcceptApplicationService {

private final ApplicationFacade applicationFacade;
private final UserFacade userFacade;
private final AuthRepository authRepository;
private final ProjectFacade projectFacade;
private final MemberRepository memberRepository;
private final NotificationRepository notificationRepository;
private final ApplicationRepository applicationRepository;

@Transactional
public void execute(Long id) {
User writer = userFacade.getCurrentUser();
User writer = authRepository.getCurrentUser();
Application application = applicationFacade.getApplication(id);
Project project = projectFacade.getProject(application.getProjectId());
Member member = memberRepository.findByUserIdAndProjectId(writer.getId(), project.getId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
@Service
public class CancelApplicationService {

private final UserFacade userFacade;
private final AuthRepository authRepository;
private final ApplicationFacade applicationFacade;

@Transactional
public void execute(Long id) {
Application application = applicationFacade.getApplication(id);
User user = userFacade.getCurrentUser();
User user = authRepository.getCurrentUser();

if(!application.isWriter(user)) {
throw new IsNotWriterException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
@RequiredArgsConstructor
public class CreateApplicationService {

private final UserFacade userFacade;
private final AuthRepository authRepository;
private final ProjectFacade projectFacade;
private final ApplicationRepository applicationRepository;
private final NotificationRepository notificationRepository;
Expand All @@ -32,7 +32,7 @@ public class CreateApplicationService {
@Transactional
public void execute(ApplicationCreateRequest request, Long id) {

User user = userFacade.getCurrentUser();
User user = authRepository.getCurrentUser();
Project project = projectFacade.getProject(id);
Member member = memberRepository.findByProjectIdAndRole(project.getId(), Role.WRITER);
User writer = userFacade.getUserById(member.getUserId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
public class FindApplicationService {

private final ApplicationFacade applicationFacade;
private final UserFacade userFacade;
private final AuthRepository authRepository;

public ApplicationResponse execute(Long id) {
Application application = applicationFacade.getApplication(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ public class FindProjectApplicationService {

private final ApplicationRepository applicationRepository;
private final MemberRepository memberRepository;
private final UserFacade userFacade;
private final AuthRepository authRepository;

@Transactional(readOnly = true)
public List<ApplicationResponse> execute(Long id) {
User user = userFacade.getCurrentUser();
User user = authRepository.getCurrentUser();
Member member = memberRepository.findByUserIdAndProjectId(user.getId(), id)
.orElseThrow(() -> MemberNotFoundException.EXCEPTION);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
@RequiredArgsConstructor
public class RejectApplicationService {

private final UserFacade userFacade;
private final AuthRepository authRepository;
private final ApplicationFacade applicationFacade;
private final ProjectFacade projectFacade;
private final MemberRepository memberRepository;
Expand All @@ -30,7 +30,7 @@ public class RejectApplicationService {

@Transactional
public void execute(Long id) {
User user = userFacade.getCurrentUser();
User user = authRepository.getCurrentUser();
Application application = applicationFacade.getApplication(id);
Member member = memberRepository.findByUserIdAndProjectId(user.getId(), application.getProjectId())
.orElseThrow(() -> MemberNotFoundException.EXCEPTION);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.woongeya.zoing.domain.auth.domain;


public record Token (
String accessToken,
String refreshToken
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.woongeya.zoing.domain.auth.exception;

import org.springframework.http.HttpStatus;

import com.woongeya.zoing.global.error.JJoingException;

public class TokenExpiredException extends JJoingException {
public TokenExpiredException() {
super(HttpStatus.FORBIDDEN, "토큰이 만료되었습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.woongeya.zoing.domain.auth.exception;

import org.springframework.http.HttpStatus;

import com.woongeya.zoing.global.error.JJoingException;

public class TokenInvalidException extends JJoingException {
public TokenInvalidException() {
super(HttpStatus.UNAUTHORIZED, "토큰이 유효하지 않습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.woongeya.zoing.domain.auth.exception;

import org.springframework.http.HttpStatus;

import com.woongeya.zoing.global.error.JJoingException;

public class TokenMissingException extends JJoingException {
public TokenMissingException() {
super(HttpStatus.UNAUTHORIZED, "토큰이 없습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.woongeya.zoing.domain.auth.exception;

import static org.springframework.http.HttpStatus.*;

import com.woongeya.zoing.global.error.JJoingException;

public class TokenNotExistException extends JJoingException {
public TokenNotExistException() {
super(FORBIDDEN, "토큰이 넘어오지 않았습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.woongeya.zoing.domain.auth.exception;

import static org.springframework.http.HttpStatus.*;

import com.woongeya.zoing.global.error.JJoingException;

public class UserIsNotAdminException extends JJoingException {
public UserIsNotAdminException() {
super(UNAUTHORIZED, "사용자가 어드민이 아닙니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.woongeya.zoing.domain.auth.exception;

import static org.springframework.http.HttpStatus.*;

import org.springframework.http.HttpStatus;

import com.woongeya.zoing.global.error.JJoingException;

public class UserNotLoginException extends JJoingException {
public UserNotLoginException() {
super(FORBIDDEN, "유저가 로그인하지 않았습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.woongeya.zoing.domain.auth.intercepter;

import static org.springframework.http.HttpHeaders.*;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import com.woongeya.zoing.domain.annotation.AdminOnly;
import com.woongeya.zoing.domain.annotation.LoginOrNot;
import com.woongeya.zoing.domain.annotation.LoginRequired;
import com.woongeya.zoing.domain.auth.exception.TokenNotExistException;
import com.woongeya.zoing.domain.auth.exception.UserIsNotAdminException;
import com.woongeya.zoing.domain.auth.repository.AuthRepository;
import com.woongeya.zoing.domain.auth.util.BearerTokenExtractor;
import com.woongeya.zoing.domain.auth.util.JwtParser;
import com.woongeya.zoing.domain.user.UserFacade;
import com.woongeya.zoing.domain.user.domain.User;
import com.woongeya.zoing.domain.user.domain.autority.Authority;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;

@Configuration
@RequiredArgsConstructor
public class AuthInterceptor implements HandlerInterceptor {

private final JwtParser jwtParser;
private final AuthRepository authRepository;
private final AuthRepository authRepository;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (handler instanceof HandlerMethod hm) {
if (hm.hasMethodAnnotation(LoginOrNot.class)) {
String bearer = request.getHeader(AUTHORIZATION);

if (bearer == null) {
authRepository.updateCurrentUser(null);
} else {
String jwt = BearerTokenExtractor.extract(bearer);
Long userId = jwtParser.getIdFromJwt(jwt);
User user = userFacade.getUserById(userId);
authRepository.updateCurrentUser(user);
}
}

if (hm.hasMethodAnnotation(LoginRequired.class)) {
if (authRepository.getCurrentUser() == null) {
throw new TokenNotExistException();
}
}
if (hm.hasMethodAnnotation(AdminOnly.class)) {
User currentUser = authRepository.getCurrentUser();
shouldUserAdmin(currentUser);
}
}

return true;
}

private static void shouldUserAdmin(User currentUser) {
if (currentUser.getAuthority() != Authority.ADMIN) {
throw new UserIsNotAdminException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.woongeya.zoing.domain.auth.presetation.dto.request.RefreshTokenRequest;
import com.woongeya.zoing.domain.auth.presetation.dto.response.TokenResponse;
import com.woongeya.zoing.domain.auth.service.OAuth2GoogleService;
import com.woongeya.zoing.domain.auth.service.RefreshTokenService;
Expand All @@ -27,12 +29,12 @@ public class AuthController {
@PostMapping("/google")
@Operation(summary = "구글 로그인")
public TokenResponse loginOfGoogle(@Validated @RequestParam(name = "code") String code) {
return googleService.execute(code);
return TokenResponse.from(googleService.execute(code));
}

@PutMapping()
@Operation(summary = "토큰 재발급")
public TokenResponse refreshToken(@RequestHeader(value = "Refresh-Token") @NotBlank String refreshToken) {
return refreshTokenService.execute(refreshToken);
public TokenResponse refreshToken(@RequestBody RefreshTokenRequest refreshToken) {
return TokenResponse.from(refreshTokenService.execute(refreshToken.refreshToken()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.woongeya.zoing.domain.auth.presetation.dto.request;

public record RefreshTokenRequest (
String refreshToken
) {
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.woongeya.zoing.domain.auth.presetation.dto.response;

import com.woongeya.zoing.domain.auth.domain.Token;

public record TokenResponse (
String accessToken,
String refreshToken
) {

public static TokenResponse of(String accessToken, String refreshToken) {
return new TokenResponse(accessToken, refreshToken);
public static TokenResponse from(Token token) {
return new TokenResponse(token.accessToken(), token.refreshToken());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.woongeya.zoing.domain.auth.repository;

import org.springframework.stereotype.Repository;
import org.springframework.web.context.annotation.RequestScope;

import com.woongeya.zoing.domain.auth.exception.UserNotLoginException;
import com.woongeya.zoing.domain.user.domain.User;

@Repository
@RequestScope
public class AuthRepository {
private User currentUser;

public User getCurrentUser() {
if (currentUser == null) {
throw new UserNotLoginException();
}
return currentUser;
}

public User getNullableCurrentUser() {
return currentUser;
}

public void updateCurrentUser(User currentUser) {
this.currentUser = currentUser;
}
}
Loading

0 comments on commit 44d18e6

Please sign in to comment.