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

✨ [Feat]: 사용자 추출 어노테이션 구현, CORS 설정, Swagger 설정 수정 #24

Merged
merged 6 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ public enum ErrorStatus implements BaseErrorCode {
AUTH_EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, "AUTH_001", "토큰이 만료되었습니다."),
AUTH_INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "AUTH_002", "토큰이 유효하지 않습니다."),
INVALID_LOGIN_REQUEST(HttpStatus.UNAUTHORIZED, "AUTH_003", "올바른 이메일이나 패스워드가 아닙니다."),
AUTH_USER_NOT_FOUND(HttpStatus.NOT_FOUND, "AUTH_004", "없는 유저 입니다.");

// User 관련
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "AUTH_004", "존재하지 않는 사용자입니다.");

private final HttpStatus httpStatus;
private final String code;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.avab.avab.apiPayload.exception.auth;
package com.avab.avab.apiPayload.exception;

import com.avab.avab.apiPayload.code.BaseErrorCode;
import com.avab.avab.apiPayload.exception.GeneralException;

public class AuthException extends GeneralException {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.avab.avab.apiPayload.exception.S3;
package com.avab.avab.apiPayload.exception;

import com.avab.avab.apiPayload.code.BaseErrorCode;
import com.avab.avab.apiPayload.exception.GeneralException;

public class S3Exception extends GeneralException {

public S3Exception(BaseErrorCode code) {
super(code);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.avab.avab.apiPayload.exception;

import com.avab.avab.apiPayload.code.BaseErrorCode;

public class UserException extends GeneralException {

public UserException(BaseErrorCode code) {
super(code);
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/avab/avab/aws/s3/AmazonS3Manager.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.avab.avab.apiPayload.code.status.ErrorStatus;
import com.avab.avab.apiPayload.exception.S3.S3Exception;
import com.avab.avab.apiPayload.exception.S3Exception;
import com.avab.avab.config.AmazonConfig;

import lombok.RequiredArgsConstructor;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/avab/avab/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.avab.avab.auth.filter.JwtRequestFilter;
import com.avab.avab.security.filter.JwtRequestFilter;

import lombok.RequiredArgsConstructor;

Expand Down
18 changes: 17 additions & 1 deletion src/main/java/com/avab/avab/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,35 @@
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.security.SecurityScheme.Type;
import io.swagger.v3.oas.models.servers.Server;

@Configuration
public class SwaggerConfig {

@Bean
public OpenAPI avabAPI() {
Info info = new Info().title("AvAb API").description("AvAb API 명세").version("0.0.1");

Components components = new Components();
String jwtSchemeName = "JWT TOKEN";
SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwtSchemeName);

Components components =
new Components()
.addSecuritySchemes(
jwtSchemeName,
new SecurityScheme()
.name(jwtSchemeName)
.type(Type.HTTP)
.scheme("Bearer")
.bearerFormat("JWT"));

return new OpenAPI()
.addServersItem(new Server().url("/"))
.info(info)
.addSecurityItem(securityRequirement)
.components(components);
}
}
34 changes: 34 additions & 0 deletions src/main/java/com/avab/avab/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.avab.avab.config;

import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.avab.avab.security.handler.resolver.AuthUserArgumentResolver;

import lombok.RequiredArgsConstructor;

@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {

private final AuthUserArgumentResolver authUserArgumentResolver;

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(false)
.maxAge(6000);
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(authUserArgumentResolver);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import com.avab.avab.service.RecreationService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.RequiredArgsConstructor;

@RestController
Expand All @@ -24,9 +24,7 @@ public class RecreationController {

@Operation(summary = "인기 레크레이션 목록 조회 API", description = "조회수를 기준으로 인기 레크레이션 목록을 조회합니다.")
@ApiResponses({
@ApiResponse(
responseCode = "COMMON200",
description = "OK, 성공"),
@ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
})
@GetMapping("/popular")
public BaseResponse<List<PopularRecreationListDTO>> getTop3RecreationsByViewCount() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.avab.avab.auth.filter;
package com.avab.avab.security.filter;

import java.io.IOException;

Expand All @@ -14,9 +14,9 @@
import org.springframework.web.filter.OncePerRequestFilter;

import com.avab.avab.apiPayload.code.status.ErrorStatus;
import com.avab.avab.apiPayload.exception.auth.AuthException;
import com.avab.avab.auth.jwt.JwtTokenProvider;
import com.avab.avab.auth.principal.PrincipalDetailsService;
import com.avab.avab.apiPayload.exception.AuthException;
import com.avab.avab.security.principal.PrincipalDetailsService;
import com.avab.avab.security.provider.JwtTokenProvider;

import lombok.RequiredArgsConstructor;

Expand Down Expand Up @@ -49,7 +49,7 @@ protected void doFilterInternal(
SecurityContextHolder.getContext()
.setAuthentication(usernamePasswordAuthenticationToken);
} else {
throw new AuthException(ErrorStatus.AUTH_USER_NOT_FOUND);
throw new AuthException(ErrorStatus.USER_NOT_FOUND);
}
} else {
throw new AuthException(ErrorStatus.AUTH_INVALID_TOKEN);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.avab.avab.security.handler.annotation;

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

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface AuthUser {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.avab.avab.security.handler.resolver;

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.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.avab.avab.apiPayload.code.status.ErrorStatus;
import com.avab.avab.apiPayload.exception.GeneralException;
import com.avab.avab.domain.User;
import com.avab.avab.service.UserService;

import lombok.RequiredArgsConstructor;

@Component
@RequiredArgsConstructor
public class AuthUserArgumentResolver implements HandlerMethodArgumentResolver {

private final UserService userService;

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(User.class);
}

@Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory)
throws Exception {
System.out.println("hihi");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

Object principal = null;
if (authentication != null) {
// 로그인하지 않은 익명 사용자라면 null 반환
if (authentication.getName().equals("anonymousUser")) {
return null;
}
principal = authentication.getPrincipal();
}
if (principal == null || principal.getClass() == String.class) {
throw new GeneralException(ErrorStatus.USER_NOT_FOUND);
}

UsernamePasswordAuthenticationToken authenticationToken =
(UsernamePasswordAuthenticationToken) authentication;
Long userId = Long.valueOf(authenticationToken.getName());

return userService.findUserById(userId);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.avab.avab.auth.principal;
package com.avab.avab.security.principal;

import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -33,7 +33,7 @@ public String getPassword() {

@Override
public String getUsername() {
return user.getUsername();
return user.getId().toString();
}

public String getEmail() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.avab.avab.auth.principal;
package com.avab.avab.security.principal;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
Expand All @@ -7,7 +7,7 @@
import org.springframework.transaction.annotation.Transactional;

import com.avab.avab.apiPayload.code.status.ErrorStatus;
import com.avab.avab.apiPayload.exception.auth.AuthException;
import com.avab.avab.apiPayload.exception.AuthException;
import com.avab.avab.domain.User;
import com.avab.avab.repository.UserRepository;

Expand All @@ -25,7 +25,7 @@ public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundExce
User user =
userRepository
.findById(Long.parseLong(userId))
.orElseThrow(() -> new AuthException(ErrorStatus.AUTH_USER_NOT_FOUND));
.orElseThrow(() -> new AuthException(ErrorStatus.USER_NOT_FOUND));

return new PrincipalDetails(user);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.avab.avab.auth.jwt;
package com.avab.avab.security.provider;

import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;
Expand All @@ -10,9 +10,15 @@
import org.springframework.stereotype.Component;

import com.avab.avab.apiPayload.code.status.ErrorStatus;
import com.avab.avab.apiPayload.exception.auth.AuthException;

import io.jsonwebtoken.*;
import com.avab.avab.apiPayload.exception.AuthException;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.security.Keys;

@Component
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.avab.avab.auth.test;
package com.avab.avab.security.test;

import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.avab.avab.apiPayload.BaseResponse;
import com.avab.avab.auth.test.dto.LoginRequest;
import com.avab.avab.auth.test.dto.LoginResponse;
import com.avab.avab.security.test.dto.LoginRequest;
import com.avab.avab.security.test.dto.LoginResponse;

import lombok.RequiredArgsConstructor;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.avab.avab.auth.test;
package com.avab.avab.security.test;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.avab.avab.auth.jwt.JwtTokenProvider;
import com.avab.avab.auth.test.dto.LoginResponse;
import com.avab.avab.domain.User;
import com.avab.avab.repository.UserRepository;
import com.avab.avab.security.provider.JwtTokenProvider;
import com.avab.avab.security.test.dto.LoginResponse;

import lombok.RequiredArgsConstructor;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.avab.avab.auth.test.dto;
package com.avab.avab.security.test.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.avab.avab.auth.test.dto;
package com.avab.avab.security.test.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/avab/avab/service/UserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.avab.avab.service;

import com.avab.avab.domain.User;

public interface UserService {

User findUserById(Long userId);
}
Loading
Loading