Skip to content
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
@@ -1,16 +1,26 @@
package cmf.commitField.domain.user.controller;

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class AuthController {
@GetMapping("/user")
public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) {
return principal.getAttributes(); // 사용자 정보 반환

@GetMapping("/login")
public ResponseEntity<?> user() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

if (authentication instanceof OAuth2AuthenticationToken) {
OAuth2User principal = (OAuth2User) authentication.getPrincipal();
return ResponseEntity.ok(principal.getAttributes()); // 사용자 정보 반환
}

return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("로그인이 필요합니다.");
}
}
}
69 changes: 69 additions & 0 deletions src/main/java/cmf/commitField/global/security/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cmf.commitField.global.security;

import org.springframework.context.annotation.Bean;
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.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
protected SecurityFilterChain config(HttpSecurity http) throws Exception {

//로그인 관련 설정
http
.oauth2Login(oauth2 -> oauth2
.loginPage("/login") // 로그인 페이지 지정
.successHandler((request, response, authentication) -> {
// 인증 정보가 SecurityContext에 추가되는 것을 보장
SecurityContextHolder.getContext().setAuthentication(authentication);

// 디버깅: authentication 정보 확인
System.out.println("Authentication: " + authentication);
System.out.println("Principal: " + authentication.getPrincipal());

if (authentication != null && authentication.getPrincipal() != null) {
//인가가 있으면 유저 정보를 저장
OAuth2User principal = (OAuth2User) authentication.getPrincipal();
String username = principal.getAttribute("login");

// 세션에 사용자 정보를 추가
request.getSession().setAttribute("user", username);

response.sendRedirect("/"); // 로그인 성공 후 리다이렉트
} else {
// 인증 실패 시 처리
response.sendRedirect("/login?error=authenticationFailed");
}
})
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 세션 정책 설정
.invalidSessionUrl("/login?error=invalidSession") // 세션이 유효하지 않으면 이동할 URL
.maximumSessions(1) // 하나의 계정으로 한 번에 로그인할 수 있도록 제한
.expiredUrl("/login?error=sessionExpired") // 세션 만료 후 이동할 URL 설정
);

//로그아웃 관련 설정
http
.logout(logout -> logout
.logoutUrl("/logout") // 로그아웃 URL 설정
.logoutSuccessUrl("/") // 로그아웃 성공 후 이동할 URL
.invalidateHttpSession(true) // 로그아웃 시 세션 무효화
.clearAuthentication(true) // 인증 정보 지우기
.deleteCookies("JSESSIONID") // 세션 쿠키 삭제
);
http
.csrf(
AbstractHttpConfigurer::disable // CSRF 보호 비활성화
);

return http.build();
}
}
Binary file added src/main/resources/static/favicon.ico
Binary file not shown.
47 changes: 47 additions & 0 deletions src/main/resources/static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GitHub OAuth2 로그인 테스트</title>
</head>
<body>
<h1>GitHub OAuth2 로그인 테스트</h1>

<!-- 로그인 버튼 -->
<a href="/oauth2/authorization/github" id="loginBtn" style="display: none;">
<button>GitHub 로그인</button>
</a>

<!-- 로그아웃 버튼 -->
<button id="logoutBtn" style="display: none;">로그아웃</button>

<h2>사용자 정보</h2>
<pre id="userInfo">로그인 후 정보를 불러옵니다...</pre>

<script>
async function fetchUser() {
try {
const response = await fetch('/login');
if (!response.ok) throw new Error("Not logged in");

const data = await response.json();
document.getElementById("userInfo").textContent = JSON.stringify(data, null, 2);
document.getElementById("logoutBtn").style.display = "block";
document.getElementById("loginBtn").style.display = "none";
} catch (error) {
document.getElementById("userInfo").textContent = "로그인이 필요합니다.";
document.getElementById("logoutBtn").style.display = "none";
document.getElementById("loginBtn").style.display = "inline-block";
}
}

document.getElementById("logoutBtn").addEventListener("click", async () => {
await fetch('/logout', { method: 'POST' }); // POST 방식으로 로그아웃
fetchUser(); // 로그아웃 후 사용자 정보 갱신
});

fetchUser(); // 페이지 로드 시 사용자 정보 가져오기
</script>
</body>
</html>