Skip to content

Commit 2205c52

Browse files
committed
쇼설 로그인 구글 연결 수정
1 parent 9df9733 commit 2205c52

10 files changed

+102
-75
lines changed

build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ dependencies {
3434
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
3535
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
3636
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'
37+
implementation 'mysql:mysql-connector-java:8.0.32'
3738
compileOnly 'org.projectlombok:lombok'
3839
runtimeOnly 'com.mysql:mysql-connector-j'
3940
annotationProcessor 'org.projectlombok:lombok'

src/main/java/codeview/main/auth/controller/OAuth2Controller.java

+8-7
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,22 @@
99
@Controller
1010
public class OAuth2Controller {
1111

12-
@GetMapping("/oauth2/callback/google")
12+
@GetMapping("/login/oauth2/code/google")
1313
public String googleCallback(@AuthenticationPrincipal OAuth2User principal, Model model) {
1414
model.addAttribute("name", principal.getAttribute("name"));
1515
return "home";
1616
}
1717

18-
@GetMapping("/oauth2/callback/github")
18+
@GetMapping("/login/oauth2/code/github")
1919
public String githubCallback(@AuthenticationPrincipal OAuth2User principal, Model model) {
2020
model.addAttribute("name", principal.getAttribute("name"));
2121
return "home";
2222
}
2323

24-
@GetMapping("/oauth2/callback/kakao")
25-
public String kakaoCallback(@AuthenticationPrincipal OAuth2User principal, Model model) {
26-
model.addAttribute("name", principal.getAttribute("nickname"));
27-
return "home";
28-
}
24+
// @GetMapping("/login/oauth2/code/kakao")
25+
// public String kakaoCallback(@AuthenticationPrincipal OAuth2User principal, Model model) {
26+
// model.addAttribute("name", principal.getAttribute("nickname"));
27+
// return "home";
28+
// }
2929
}
30+

src/main/java/codeview/main/auth/dto/OAuth2UserInfo.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ public static OAuth2UserInfo of(String registrationId, Map<String, Object> attri
2020
return ofGoogle(attributes);
2121
case "kakao":
2222
return ofKakao(attributes);
23+
case "github":
24+
return ofGithub(attributes);
2325
default:
24-
throw new IllegalArgumentException("Illegal registration ID: " + registrationId);
26+
throw new IllegalArgumentException("Unsupported registration ID: " + registrationId);
2527
}
2628
}
2729

@@ -44,6 +46,14 @@ private static OAuth2UserInfo ofKakao(Map<String, Object> attributes) {
4446
.build();
4547
}
4648

49+
private static OAuth2UserInfo ofGithub(Map<String, Object> attributes) {
50+
return OAuth2UserInfo.builder()
51+
.name((String) attributes.get("login"))
52+
.email((String) attributes.get("email"))
53+
.profile((String) attributes.get("avatar_url"))
54+
.build();
55+
}
56+
4757
public Member toEntity() {
4858
return Member.builder()
4959
.name(name)

src/main/java/codeview/main/auth/dto/model/PrincipalDetails.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ public PrincipalDetails(Member member, Map<String, Object> attributes, String at
2323

2424
@Override
2525
public String getName() {
26-
return attributes.get(attributeKey).toString();
26+
// If attributeKey is null or not present, fallback to member's email or name
27+
return attributes.getOrDefault(attributeKey, member.getName() != null ? member.getName() : member.getEmail()).toString();
2728
}
2829

2930
@Override

src/main/java/codeview/main/auth/handler/OAuth2SuccessHandler.java

+7-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import codeview.main.auth.jwt.TokenProvider;
44
import com.fasterxml.jackson.databind.ObjectMapper;
55
import lombok.RequiredArgsConstructor;
6-
import org.springframework.http.HttpStatus;
76
import org.springframework.security.core.Authentication;
87
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
98
import org.springframework.stereotype.Component;
@@ -20,25 +19,22 @@
2019
public class OAuth2SuccessHandler implements AuthenticationSuccessHandler {
2120

2221
private final TokenProvider tokenProvider;
22+
private final ObjectMapper objectMapper = new ObjectMapper();
2323

2424
@Override
2525
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
2626
Authentication authentication) throws IOException, ServletException {
27-
27+
// JWT 토큰 생성
2828
String accessToken = tokenProvider.generateAccessToken(authentication);
2929
String refreshToken = tokenProvider.generateRefreshToken(authentication, accessToken);
3030

31-
32-
Map<String, Object> responseBody = new HashMap<>();
33-
responseBody.put("code", 200);
34-
Map<String, String> result = new HashMap<>();
35-
result.put("accessToken", accessToken);
36-
result.put("refreshToken", refreshToken);
37-
responseBody.put("result", result);
31+
// JSON 형태로 응답
32+
Map<String, String> tokens = new HashMap<>();
33+
tokens.put("accessToken", accessToken);
34+
tokens.put("refreshToken", refreshToken);
3835

3936
response.setContentType("application/json");
4037
response.setCharacterEncoding("UTF-8");
41-
response.getWriter().write(new ObjectMapper().writeValueAsString(responseBody));
42-
response.setStatus(HttpStatus.OK.value());
38+
response.getWriter().write(objectMapper.writeValueAsString(tokens));
4339
}
4440
}

src/main/java/codeview/main/auth/jwt/TokenAuthenticationFilter.java

+12-30
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,33 @@
44
import jakarta.servlet.ServletException;
55
import jakarta.servlet.http.HttpServletRequest;
66
import jakarta.servlet.http.HttpServletResponse;
7-
import lombok.RequiredArgsConstructor;
87
import org.springframework.security.core.Authentication;
98
import org.springframework.security.core.context.SecurityContextHolder;
109
import org.springframework.stereotype.Component;
11-
import org.springframework.util.ObjectUtils;
12-
import org.springframework.util.StringUtils;
1310
import org.springframework.web.filter.OncePerRequestFilter;
1411

1512
import java.io.IOException;
1613

17-
@RequiredArgsConstructor
1814
@Component
1915
public class TokenAuthenticationFilter extends OncePerRequestFilter {
2016

2117
private final TokenProvider tokenProvider;
2218

23-
@Override
24-
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
25-
FilterChain filterChain) throws ServletException, IOException {
26-
String accessToken = resolveToken(request);
27-
28-
if (tokenProvider.validateToken(accessToken)) {
29-
setAuthentication(accessToken);
30-
} else {
31-
String reissueAccessToken = tokenProvider.reissueAccessToken(accessToken);
19+
public TokenAuthenticationFilter(TokenProvider tokenProvider) {
20+
this.tokenProvider = tokenProvider;
21+
}
3222

33-
if (StringUtils.hasText(reissueAccessToken)) {
34-
setAuthentication(reissueAccessToken);
35-
response.setHeader("Authorization", "Bearer " + reissueAccessToken);
23+
@Override
24+
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
25+
throws ServletException, IOException {
26+
String bearerToken = request.getHeader("Authorization");
27+
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
28+
String token = bearerToken.substring(7);
29+
Authentication authentication = tokenProvider.getAuthentication(token);
30+
if (authentication != null) {
31+
SecurityContextHolder.getContext().setAuthentication(authentication);
3632
}
3733
}
38-
3934
filterChain.doFilter(request, response);
4035
}
41-
42-
private void setAuthentication(String accessToken) {
43-
Authentication authentication = tokenProvider.getAuthentication(accessToken);
44-
SecurityContextHolder.getContext().setAuthentication(authentication);
45-
}
46-
47-
private String resolveToken(HttpServletRequest request) {
48-
String token = request.getHeader("Authorization");
49-
if (ObjectUtils.isEmpty(token) || !token.startsWith("Bearer ")) {
50-
return null;
51-
}
52-
return token.substring(7);
53-
}
5436
}

src/main/java/codeview/main/auth/service/CustomOAuth2UserService.java

+32-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.springframework.stereotype.Service;
1414

1515
import java.util.Map;
16+
import java.util.Optional;
1617

1718
@RequiredArgsConstructor
1819
@Service
@@ -23,19 +24,46 @@ public class CustomOAuth2UserService extends DefaultOAuth2UserService {
2324
@Transactional
2425
@Override
2526
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
26-
Map<String, Object> oAuth2UserAttributes = super.loadUser(userRequest).getAttributes();
27+
OAuth2User oAuth2User = super.loadUser(userRequest);
28+
Map<String, Object> oAuth2UserAttributes = oAuth2User.getAttributes();
29+
2730
String registrationId = userRequest.getClientRegistration().getRegistrationId();
2831
String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails()
2932
.getUserInfoEndpoint().getUserNameAttributeName();
3033

3134
OAuth2UserInfo oAuth2UserInfo = OAuth2UserInfo.of(registrationId, oAuth2UserAttributes);
32-
Member member = getOrSave(oAuth2UserInfo);
35+
36+
// 이메일이 없는 경우 처리
37+
Optional<Member> memberOptional = Optional.empty();
38+
if (oAuth2UserInfo.getEmail() != null) {
39+
memberOptional = memberRepository.findByEmail(oAuth2UserInfo.getEmail());
40+
}
41+
42+
Member member;
43+
if (memberOptional.isPresent()) {
44+
member = memberOptional.get();
45+
} else {
46+
// 이메일이 없거나 기존 회원이 아닌 경우 새로 저장
47+
member = getOrSave(oAuth2UserInfo);
48+
}
3349

3450
return new PrincipalDetails(member, oAuth2UserAttributes, userNameAttributeName);
3551
}
3652

3753
private Member getOrSave(OAuth2UserInfo oAuth2UserInfo) {
38-
return memberRepository.findByEmail(oAuth2UserInfo.getEmail())
39-
.orElseGet(() -> memberRepository.save(oAuth2UserInfo.toEntity()));
54+
Member member = new Member();
55+
member.setName(oAuth2UserInfo.getName());
56+
member.setProfile(oAuth2UserInfo.getProfile());
57+
58+
if (oAuth2UserInfo.getEmail() != null) {
59+
member.setEmail(oAuth2UserInfo.getEmail());
60+
} else {
61+
// 이메일이 없는 경우 다른 방법으로 식별자를 생성 (예: OAuth 제공자의 고유 ID 사용)
62+
member.setEmail(oAuth2UserInfo.getName() + "@example.com");
63+
}
64+
65+
member.setRole(Member.Role.ROLE_USER);
66+
67+
return memberRepository.save(member);
4068
}
4169
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package codeview.main.config;
2+
3+
import org.springframework.stereotype.Component;
4+
import org.springframework.web.filter.OncePerRequestFilter;
5+
6+
import jakarta.servlet.FilterChain;
7+
import jakarta.servlet.ServletException;
8+
import jakarta.servlet.http.HttpServletRequest;
9+
import jakarta.servlet.http.HttpServletResponse;
10+
import java.io.IOException;
11+
12+
@Component
13+
public class CustomRequestFilter extends OncePerRequestFilter {
14+
15+
@Override
16+
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
17+
throws ServletException, IOException {
18+
String uri = request.getRequestURI();
19+
if (!uri.startsWith("/login") && !uri.startsWith("/oauth2")) {
20+
request.getSession().setAttribute("redirectUri", request.getRequestURL().toString());
21+
}
22+
filterChain.doFilter(request, response);
23+
}
24+
}

src/main/java/codeview/main/config/SecurityConfig.java

+4-20
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import codeview.main.auth.handler.OAuth2SuccessHandler;
44
import codeview.main.auth.jwt.TokenAuthenticationFilter;
55
import codeview.main.auth.jwt.TokenExceptionFilter;
6-
import codeview.main.auth.jwt.TokenProvider;
76
import codeview.main.auth.service.CustomOAuth2UserService;
87
import lombok.RequiredArgsConstructor;
98
import org.springframework.context.annotation.Bean;
@@ -19,8 +18,8 @@
1918
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
2019
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
2120
import org.springframework.web.cors.CorsConfiguration;
21+
import org.springframework.web.cors.CorsConfigurationSource;
2222
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
23-
import org.springframework.web.filter.CorsFilter;
2423

2524
import java.util.Arrays;
2625

@@ -32,7 +31,7 @@ public class SecurityConfig {
3231

3332
private final CustomOAuth2UserService customOAuth2UserService;
3433
private final TokenAuthenticationFilter tokenAuthenticationFilter;
35-
private final TokenProvider tokenProvider;
34+
private final OAuth2SuccessHandler successHandler;
3635

3736
@Bean
3837
public WebSecurityCustomizer webSecurityCustomizer() {
@@ -49,7 +48,6 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
4948
.logout(AbstractHttpConfigurer::disable)
5049
.headers(c -> c.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable).disable())
5150
.sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
52-
5351
.authorizeHttpRequests(request -> request.requestMatchers(
5452
new AntPathRequestMatcher("/"),
5553
new AntPathRequestMatcher("/home"),
@@ -58,35 +56,21 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
5856
new AntPathRequestMatcher("/api/oauth2/**")
5957
).permitAll()
6058
.anyRequest().authenticated())
61-
6259
.oauth2Login(oauth -> oauth
6360
.loginPage("/login")
64-
.successHandler(new OAuth2SuccessHandler(tokenProvider))
61+
.successHandler(successHandler)
6562
.userInfoEndpoint(userInfo -> userInfo
6663
.userService(customOAuth2UserService)))
6764
.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
6865
.addFilterBefore(new TokenExceptionFilter(), TokenAuthenticationFilter.class)
69-
7066
.exceptionHandling((exceptions) -> exceptions
7167
.authenticationEntryPoint(new CustomAuthenticationEntryPoint())
7268
.accessDeniedHandler(new CustomAccessDeniedHandler()));
7369
return http.build();
7470
}
7571

7672
@Bean
77-
public CorsFilter corsFilter() {
78-
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
79-
CorsConfiguration config = new CorsConfiguration();
80-
config.setAllowCredentials(true);
81-
config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
82-
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
83-
config.setAllowedHeaders(Arrays.asList("*"));
84-
source.registerCorsConfiguration("/**", config);
85-
return new CorsFilter(source);
86-
}
87-
88-
@Bean
89-
public UrlBasedCorsConfigurationSource corsConfigurationSource() {
73+
public CorsConfigurationSource corsConfigurationSource() {
9074
CorsConfiguration config = new CorsConfiguration();
9175
config.setAllowCredentials(true);
9276
config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));

src/main/resources/application.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ spring:
22
profiles:
33
active: local
44
group:
5-
local: local, common, secret-dev
5+
local: local, common, secret
66
blue: blue, common, secret-deploy
77
green: green, common, secret-deploy
88

0 commit comments

Comments
 (0)