Skip to content

Commit

Permalink
Merge branch 'develop' into test
Browse files Browse the repository at this point in the history
  • Loading branch information
gerry-mandering committed May 7, 2024
2 parents dcc5c6d + 268a60c commit b6ccf32
Show file tree
Hide file tree
Showing 37 changed files with 757 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import com.example.dreamvalutbackend.config.exception.JwtAuthenticationEntryPoint;
import com.example.dreamvalutbackend.config.handler.CommonLoginSuccessHandler;
import com.example.dreamvalutbackend.config.jwt.filter.JwtVerifyFilter;
import com.example.dreamvalutbackend.config.oauth2.service.OAuth2UserService;
Expand Down Expand Up @@ -46,6 +47,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
authorizationManagerRequestMatcherRegistry.anyRequest().permitAll()) //모든 요청 인증없이 허용
.addFilterBefore(jwtVerifyFilter(), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(httpSecurityExceptionHandlingConfigurer ->
httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint(jwtAuthenticationEntryPoint()))
// .authenticationProvider(authenticationProvider()).addFilterBefore(jwtAuthFIlter, UsernamePasswordAuthenticationFilter.class);
.formLogin(httpSecurityFormLoginConfigurer ->
httpSecurityFormLoginConfigurer
Expand Down Expand Up @@ -74,7 +77,10 @@ public JwtVerifyFilter jwtVerifyFilter() {
public CommonLoginSuccessHandler commonLoginSuccessHandler() {
return new CommonLoginSuccessHandler(tokenRepository);
}

@Bean
public JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint() {
return new JwtAuthenticationEntryPoint();
}


@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example.dreamvalutbackend.config.exception;

import java.io.IOException;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

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

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {

response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.io.PrintWriter;
Expand All @@ -24,12 +26,12 @@
@Slf4j
@Component
@RequiredArgsConstructor
public class CommonLoginSuccessHandler implements AuthenticationSuccessHandler {
public class CommonLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

private final TokenRepository tokenRepository;

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {

UserDetailPrincipal principal = (UserDetailPrincipal) authentication.getPrincipal();

Expand All @@ -42,23 +44,28 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
Token token = new Token(refreshToken, userId);
tokenRepository.save(token);

String targetUrl = determineTargetUrl(request, response, accessToken, refreshToken);

response.addCookie(createCookie("accessToken", accessToken, JwtConstants.ACCESS_EXP_TIME, false, false));
getRedirectStrategy().sendRedirect(request, response, targetUrl);

response.addCookie(createCookie("refreshToken", refreshToken, JwtConstants.REFRESH_EXP_TIME, false, false));

String clientUrl = "http://localhost:3000/genre_select";
response.sendRedirect(clientUrl);
}

private Cookie createCookie(String name, String value, int maxAge, boolean httpOnly, boolean secure) {
Cookie cookie = new Cookie(name, value);
cookie.setMaxAge(maxAge);
cookie.setHttpOnly(httpOnly);
// cookie.setSecure(secure);
cookie.setPath("/");
return cookie;
protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response, String accessToken, String refreshToken) {
String redirectUri = request.getParameter("redirect_uri");
// if (redirectUri == null) {
// redirectUri = getDefaultTargetUrl();
// }

if (redirectUri == null) {
redirectUri = "http://localhost:3000/genre_select"; // 기본값 설정
}

return UriComponentsBuilder.fromUriString(redirectUri)
.queryParam("accessToken", accessToken)
.queryParam("refreshToken", refreshToken)
.build().toUriString();
}


}

Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@

@Slf4j
public class JwtVerifyFilter extends OncePerRequestFilter {

private static final String[] whitelist = { "/signUp", "/login", "/refresh", "/tracks", "/tracks/**", "/playlists",
"/playlists/**", "/tags", "/tags/**", "/genres", "/genres/**", "/search" };
"/playlists/**", "/tags", "/tags/**", "/genres", "/genres/**", "/search", "/user", "/users/**" };

private static void checkAuthorizationHeader(String header) {
if (header == null) {
Expand Down Expand Up @@ -58,8 +59,10 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
String json = "";
if (e instanceof CustomExpiredJwtException) {
json = gson.toJson(Map.of("Token_Expired", e.getMessage()));
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
} else {
json = gson.toJson(Map.of("error", e.getMessage()));
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}

response.setContentType("application/json; charset=UTF-8");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;

import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
Expand Down Expand Up @@ -75,8 +78,8 @@ public static Map<String, Object> validateToken(String token) {
.build()
.parseClaimsJws(token) // 파싱 및 검증, 실패 시 에러
.getBody();
} catch(ExpiredJwtException expiredJwtException){
throw new CustomExpiredJwtException("토큰이 만료되었습니다", expiredJwtException);
}catch (ExpiredJwtException expiredJwtException) {
throw new AuthenticationServiceException("토큰이 만료되었습니다", expiredJwtException);
} catch(Exception e){
throw new CustomJwtException("Error");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.example.dreamvalutbackend.config.oauth2.domain;

import java.util.Map;

public class GoogleUserInfo implements OAuth2UserInfo {
private String socialId;
private String email;
private String name;
private String image;

public GoogleUserInfo(Map<String, Object> attributes) {
this.socialId = String.valueOf(attributes.get("sub"));
this.email = String.valueOf(attributes.get("email"));
this.name = String.valueOf(attributes.get("name"));
this.image = String.valueOf(attributes.get("picture"));
}

public String getSocialId() {
return socialId;
}

public String getEmail() {
return email;
}

public String getName() {
return name;
}

public String getImage() {
return image;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.util.Map;

public class KakaoUserInfo {
public class KakaoUserInfo implements OAuth2UserInfo {
public static String socialId;
public static Map<String, Object> account;
public static Map<String, Object> profile;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.example.dreamvalutbackend.config.oauth2.domain;

import java.util.Map;

public class NaverUserInfo implements OAuth2UserInfo {
public static String socialId;
public static Map<String, Object> responseMap;
public NaverUserInfo(Map<String, Object> attributes) {
responseMap = (Map<String, Object>) attributes.get("response");
}

public String getSocialId() {
return String.valueOf(responseMap.get("id"));
}

public String getEmail() {
return String.valueOf(responseMap.get("email"));
}
public String getName() {
return String.valueOf(responseMap.get("name"));
}
public String getImage() {
return String.valueOf(responseMap.get("profile_image"));
}




}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.example.dreamvalutbackend.config.oauth2.domain;

public interface OAuth2UserInfo {
String getSocialId();
String getName();
String getEmail();
String getImage();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

import com.example.dreamvalutbackend.config.oauth2.domain.GoogleUserInfo;
import com.example.dreamvalutbackend.config.oauth2.domain.KakaoUserInfo;
import com.example.dreamvalutbackend.config.oauth2.domain.NaverUserInfo;
import com.example.dreamvalutbackend.config.oauth2.domain.OAuth2UserInfo;
import com.example.dreamvalutbackend.domain.user.domain.SocialType;
import com.example.dreamvalutbackend.domain.user.domain.User;
import com.example.dreamvalutbackend.domain.user.domain.UserDetailPrincipal;
import com.example.dreamvalutbackend.domain.user.domain.UserRole;
Expand All @@ -32,30 +37,39 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic

OAuth2User oAuth2User = super.loadUser(userRequest);
Map<String, Object> attributes = oAuth2User.getAttributes();

// nameAttributeKey
String userNameAttributeName = userRequest.getClientRegistration()
.getProviderDetails()
.getUserInfoEndpoint()
.getUserNameAttributeName();

KakaoUserInfo kakaoUserInfo = new KakaoUserInfo(attributes);
String socialId = kakaoUserInfo.getSocialId();
String name = kakaoUserInfo.getName();
String email = kakaoUserInfo.getEmail();
String profile = kakaoUserInfo.getImage();
String displayName = kakaoUserInfo.getName();
String registrationId = userRequest.getClientRegistration().getRegistrationId();
SocialType socialType = SocialType.valueOf(registrationId.toUpperCase());

OAuth2UserInfo userInfo;
switch (registrationId) {
case "google":
userInfo = (OAuth2UserInfo)new GoogleUserInfo(attributes);
break;
case "naver":
userInfo = (OAuth2UserInfo)new NaverUserInfo(attributes);
break;
case "kakao":
default:
userInfo = (OAuth2UserInfo)new KakaoUserInfo(attributes);
break;
}

String socialId = userInfo.getSocialId();
String name = userInfo.getName();
String email = userInfo.getEmail();
String profile = userInfo.getImage();
String displayName = userInfo.getName();


// 소셜 ID 로 사용자를 조회, 없으면 socialId 와 이름으로 사용자 생성
Optional<User> bySocialId = userRepository.findBySocialId(socialId);
User user = bySocialId.orElseGet(() -> saveSocialMember(socialId, name, email, profile, displayName));
User user = bySocialId.orElseGet(() -> saveSocialMember(socialId, name, email, profile, displayName, socialType));

return new UserDetailPrincipal(user, Collections.singleton(new SimpleGrantedAuthority(user.getRole().getValue())),attributes);
}

public User saveSocialMember(String socialId, String name, String email, String profile, String displayName) {
User newMember = User.builder().socialId(socialId).userName(name).userEmail(email).profileImage(profile).role(UserRole.USER).displayName(displayName).build();
public User saveSocialMember(String socialId, String name, String email, String profile, String displayName, SocialType socialType) {
User newMember = User.builder().socialId(socialId).userName(name).userEmail(email).profileImage(profile).role(UserRole.USER).displayName(displayName).type(socialType).build();
return userRepository.save(newMember);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.dreamvalutbackend.config.swagger;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

Expand All @@ -8,9 +9,14 @@
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.servers.Server;

@Configuration
public class SwaggerConfig {

@Value("${domain.test}")
private String domainUrl;

@Bean
public OpenAPI openAPI() {
String jwt = "JWT";
Expand All @@ -28,7 +34,9 @@ public OpenAPI openAPI() {
return new OpenAPI()
.components(components)
.info(apiInfo())
.addSecurityItem(securityRequirement);
.addSecurityItem(securityRequirement)
.addServersItem(new Server().url("http://localhost:8080"))
.addServersItem(new Server().url(domainUrl));
}

private Info apiInfo() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ public class Genre extends BaseTimeEntity {
@Column(nullable = false)
private String genreImage;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

// @OneToMany(mappedBy = "genre", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
// private List<Track> tracks = new ArrayList<>();

Expand Down
Loading

0 comments on commit b6ccf32

Please sign in to comment.