Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'

// Web Client
implementation 'org.springframework.boot:spring-boot-starter-webflux'

// Spring Security & OAuth2
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse

// accessToken 이 필요없는 경우 필터링 없이 처리
if (requestURI.startsWith("/api/auth/token") ||
requestURI.startsWith("/oauth2")) { // oauth2/authorization/facebook
requestURI.startsWith("/api/auth/login/facebook")) {
chain.doFilter(request, response);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
public class OpenApiConfig {

private static final String BEARER_TOKEN_PREFIX = "bearer";
private static String securityJwtName = "JWT";
private static final String securityJwtName = "JWT";

@Bean
public OpenAPI customOpenAPI() {
Expand Down
37 changes: 16 additions & 21 deletions src/main/java/com/olive/pribee/global/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
Expand All @@ -15,9 +16,6 @@
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import com.olive.pribee.global.common.filter.JwtAuthenticationFilter;
import com.olive.pribee.module.auth.handler.OAuth2AuthenticationFailureHandler;
import com.olive.pribee.module.auth.handler.OAuth2AuthenticationSuccessHandler;
import com.olive.pribee.module.auth.service.CustomOAuth2UserService;

import lombok.RequiredArgsConstructor;

Expand All @@ -26,36 +24,34 @@
@RequiredArgsConstructor
public class SecurityConfig {

@Value("${front.url}")
@Value("${url.test}")
private String TEST_URL;

@Value("${url.front}")
private String FRONT_URL;

@Value("${url.domain}")
private String DOMAIN_URL;

private final JwtAuthenticationFilter jwtAuthenticationFilter;
private final CustomOAuth2UserService customOAuth2UserService;
private final OAuth2AuthenticationSuccessHandler successHandler;
private final OAuth2AuthenticationFailureHandler failureHandler;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers(
"/api/auth/token",
"/oauth2/**",
"/api/auth/login/facebook",
"/swagger-ui/**",
"/webjars/**",
"/swagger-ui.html",
"/v3/api-docs/**").permitAll()
"/v3/api-docs/**"
).permitAll()
.anyRequest().authenticated()
)

// OAuth2 로그인 설정
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService))
.successHandler(successHandler)
.failureHandler(failureHandler)
)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

return http.build();
Expand All @@ -65,15 +61,14 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
public CorsConfigurationSource corsConfigurationSource() {
// 허용할 출처, HTTP 메서드, 헤더 설정 및 자격 증명 포함 설정
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of(FRONT_URL));
configuration.setAllowedOrigins(List.of(TEST_URL, FRONT_URL, DOMAIN_URL));
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
configuration.setAllowedHeaders(List.of("*"));
configuration.setAllowCredentials(true);

// 특정 API 경로에 대해 CORS 정책을 적용
// 특정 API 경로에 대해 CORS 정책 제외
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
source.registerCorsConfiguration("/oauth2/**", configuration);
source.registerCorsConfiguration("/swagger-ui/**", configuration);
source.registerCorsConfiguration("/v3/api-docs/**", configuration);
source.registerCorsConfiguration("/webjars/**", configuration);
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/olive/pribee/global/config/WebClientConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.olive.pribee.global.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {

@Bean
public WebClient.Builder webClientBuilder() {
return WebClient.builder()
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

@Getter
public enum GlobalErrorCode implements ErrorCode {
INVALID_FACEBOOK_CODE(HttpStatus.UNAUTHORIZED, "facebook code가 유효하지 않습니다."),
AUTHENTICATION_FAILED(HttpStatus.UNAUTHORIZED, "인증에 실패하였습니다."),
AUTHORIZATION_FAILED(HttpStatus.UNAUTHORIZED, "인가에 실패하였습니다."),
ACCESS_TOKEN_REQUIRED(HttpStatus.UNAUTHORIZED, "Access Token이 필요합니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@
public class MemberController implements MemberControllerDocs {
private final MemberService memberService;

@GetMapping("/login/facebook")
public ResponseEntity<ResponseDto> getLogin(@RequestHeader("facebook-code") String code){
LoginResDto resDto = memberService.getAccessToken(code);
return ResponseEntity.status(201).body(DataResponseDto.of(resDto, 201));
}

@GetMapping("/token")
public ResponseEntity<ResponseDto> getAccessToken(@RequestHeader("Authorization-Refresh") String refreshToken) {
LoginResDto resDto = memberService.getAccessToken(refreshToken);
LoginResDto resDto = memberService.getNewAccessToken(refreshToken);
return ResponseEntity.status(201).body(DataResponseDto.of(resDto, 201));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,29 @@
@Tag(name = "Member", description = "사용자 관련 API")
public interface MemberControllerDocs {

@Operation(summary = "accessToken 발급", description = "리프레시 토큰을 이용해 엑세스 토큰을 발급합니다.")
@Operation(summary = "로그인", description = "facebook code 를 통해 로그인을 발급합니다.")
@ApiResponses({
@ApiResponse(responseCode = "201", description = "Created",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseDto.class),
examples =
@ExampleObject(value = "{ \"code\": 201, \"message\": \"Created\" }")
)
),
@ApiResponse(responseCode = "401", description = "인증에 실패하였습니다.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ResponseDto.class),
examples =
@ExampleObject(value = "{ \"code\": 401, \"message\": \"facebook code가 유효하지 않습니다.\" }")

)
)
})
ResponseEntity<ResponseDto> getLogin(String code);

@Operation(summary = "accessToken 재발급", description = "리프레시 토큰을 이용해 엑세스 토큰을 발급합니다.")
@ApiResponses({
@ApiResponse(responseCode = "201", description = "Created",
content = @Content(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ public class Member extends BaseTime {
@NotNull
private String name;

@NotNull
private String email;

@NotNull
Expand All @@ -51,7 +50,7 @@ public class Member extends BaseTime {
@Enumerated(EnumType.STRING)
private MemberRole role;

public static Member of(@NotNull String facebookId,@NotNull String name, @NotNull String email, @NotNull String profilePictureUrl) {
public static Member of(@NotNull String facebookId,@NotNull String name, String email, @NotNull String profilePictureUrl) {
return Member.builder()
.facebookId(facebookId)
.name(name)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.olive.pribee.module.auth.dto.res;

import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FacebookAuthRes {

private String facebookId;
private String longTermToken;

@Builder
public FacebookAuthRes(
@JsonProperty("facebookId") String facebookId,
@JsonProperty("longTermToken") String longTermToken

) {
this.facebookId = facebookId;
this.longTermToken = longTermToken;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.olive.pribee.module.auth.dto.res;

import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FacebookTokenRes {
private String accessToken;
private String tokenType;
private long expiresIn;

@Builder
public FacebookTokenRes(
@JsonProperty("access_token") String accessToken,
@JsonProperty("token_type") String tokenType,
@JsonProperty("expires_in") long expiresIn
) {
this.accessToken = accessToken;
this.tokenType = tokenType;
this.expiresIn = expiresIn;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.olive.pribee.module.auth.dto.res;

import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FacebookUserInfoPictureRes {

private Data data;

@Builder
public FacebookUserInfoPictureRes(@JsonProperty("data") Data data) {
this.data = data;
}

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class Data {
private int height;
private boolean isSilhouette;
private String url;
private int width;

@Builder
public Data(
@JsonProperty("height") int height,
@JsonProperty("is_silhouette") boolean isSilhouette,
@JsonProperty("url") String url,
@JsonProperty("width") int width
) {
this.height = height;
this.isSilhouette = isSilhouette;
this.url = url;
this.width = width;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.olive.pribee.module.auth.dto.res;

import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FacebookUserInfoRes {
private String id;
private String name;
private String email;
private FacebookUserInfoPictureRes picture;

@Builder
public FacebookUserInfoRes(
@JsonProperty("id") String id,
@JsonProperty("name") String name,
@JsonProperty("email") String email,
@JsonProperty("picture") FacebookUserInfoPictureRes picture
) {
this.id = id;
this.name = name;
this.email = email;
this.picture = picture;
}

}

This file was deleted.

Loading