아래는 "스프링 시큐리티" 책의 7장에 포함될 "OAuth2 기본 개념", "구글 등 소셜 로그인 구현", 그리고 "커스텀 OAuth2 클라이언트 설정"에 대한 내용입니다. 개념을 명확히 하고 실습 가능한 예제를 포함해 실무 적용성을 높였습니다. --- ### 7장. OAuth2와 소셜 로그인 #### 7.1 OAuth2 기본 개념 **OAuth2**는 인증(Authentication)과 권한 부여(Authorization)를 위한 표준 프로토콜로, 사용자가 자신의 자격 증명을 직접 공유하지 않고도 제3자 애플리케이션이 리소스에 접근할 수 있도록 합니다. 소셜 로그인(구글, 페이스북 등)이나 API 인증에 널리 사용됩니다. ##### OAuth2의 주요 구성 요소 - **Resource Owner**: 리소스를 소유한 사용자(예: 구글 계정 소유자). - **Client**: 리소스에 접근하려는 애플리케이션(우리의 스프링 앱). - **Authorization Server**: 사용자를 인증하고 토큰을 발급하는 서버(예: 구글 인증 서버). - **Resource Server**: 보호된 리소스를 제공하는 서버(예: 구글 API). - **Access Token**: 클라이언트가 리소스에 접근할 때 사용하는 키. ##### 인증 흐름 (Authorization Code Grant) 가장 흔히 사용되는 흐름으로, 소셜 로그인에 적합합니다: 1. 사용자가 클라이언트에서 "구글로 로그인" 버튼을 클릭. 2. 클라이언트가 사용자를 Authorization Server로 리다이렉트. 3. 사용자가 로그인 후 권한을 승인하면 Authorization Code가 클라이언트로 반환. 4. 클라이언트가 코드를 Access Token으로 교환. 5. Access Token으로 Resource Server에서 사용자 정보를 가져옴. 스프링 시큐리티는 OAuth2를 쉽게 통합할 수 있도록 `spring-security-oauth2-client` 모듈을 제공하며, 최소한의 설정으로 소셜 로그인을 구현할 수 있습니다. #### 7.3 구글, 깃허브 등 소셜 로그인 구현 스프링 시큐리티를 사용하면 구글, 깃허브 같은 소셜 로그인을 빠르게 구현할 수 있습니다. 여기서는 구글 로그인을 예로 설명합니다. ##### 1. 의존성 추가 `pom.xml`에 다음 의존성을 추가: ```xml org.springframework.boot spring-boot-starter-oauth2-client org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-thymeleaf ``` ##### 2. 구글 OAuth2 클라이언트 등록 1. [Google Cloud Console](https://console.cloud.google.com)에서 프로젝트 생성. 2. "OAuth 2.0 클라이언트 ID" 생성: - 애플리케이션 유형: 웹 애플리케이션. - 리다이렉트 URI: `http://localhost:8080/login/oauth2/code/google`. 3. 클라이언트 ID와 클라이언트 비밀번호(Secret)를 발급받음. ##### 3. 설정 파일 작성 `application.yml`에 구글 OAuth2 설정 추가: ```yaml spring: security: oauth2: client: registration: google: client-id: your-google-client-id client-secret: your-google-client-secret scope: profile, email provider: google: authorization-uri: https://accounts.google.com/o/oauth2/v2/auth token-uri: https://oauth2.googleapis.com/token user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo user-name-attribute: email ``` ##### 4. SecurityConfig 설정 ```java 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.web.SecurityFilterChain; @Configuration public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/", "/login").permitAll() .anyRequest().authenticated() ) .oauth2Login(oauth2 -> oauth2 .loginPage("/login") // 커스텀 로그인 페이지 .defaultSuccessUrl("/home") // 로그인 성공 시 이동 ) .logout(logout -> logout.logoutSuccessUrl("/")); return http.build(); } } ``` ##### 5. 로그인 페이지 제작 `src/main/resources/templates/login.html`: ```html Login

로그인

구글로 로그인 ``` - `/oauth2/authorization/google`은 스프링 시큐리티가 자동 생성한 구글 로그인 경로. ##### 6. 사용자 정보 확인 로그인 성공 후 `Principal` 객체로 사용자 정보를 가져올 수 있습니다: ```java import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller public class HomeController { @GetMapping("/home") public String home(@AuthenticationPrincipal OAuth2User oAuth2User, Model model) { model.addAttribute("name", oAuth2User.getAttribute("name")); model.addAttribute("email", oAuth2User.getAttribute("email")); return "home"; } } ``` `home.html`: ```html

환영합니다, !

이메일:

로그아웃 ``` ##### 깃허브 로그인 추가 `application.yml`에 깃허브 설정 추가: ```yaml spring: security: oauth2: client: registration: github: client-id: your-github-client-id client-secret: your-github-client-secret scope: read:user ``` 로그인 링크: `깃허브로 로그인`. ##### 동작 원리 1. 사용자가 구글 로그인 링크를 클릭하면 구글 인증 서버로 리다이렉트. 2. 구글에서 인증 후 리다이렉트 URI로 코드를 반환. 3. 스프링 시큐리티가 코드를 토큰으로 교환하고, 사용자 정보를 가져와 `OAuth2User`로 저장. 4. 인증 성공 시 `/home`으로 이동. #### 7.4 커스텀 OAuth2 클라이언트 설정 스프링 시큐리티의 기본 설정으로 지원되지 않는 제공자(예: 네이버, 카카오)나 고급 요구사항을 처리하려면 커스텀 OAuth2 클라이언트를 설정해야 합니다. ##### 네이버 로그인 예제 1. **네이버 개발자 센터**에서 클라이언트 ID와 Secret 발급. 2. `application.yml`에 추가: ```yaml spring: security: oauth2: client: registration: naver: client-id: your-naver-client-id client-secret: your-naver-client-secret redirect-uri: "{baseUrl}/login/oauth2/code/naver" authorization-grant-type: authorization_code scope: name, email provider: naver: authorization-uri: https://nid.naver.com/oauth2.0/authorize token-uri: https://nid.naver.com/oauth2.0/token user-info-uri: https://openapi.naver.com/v1/nid/me user-name-attribute: response # 네이버는 사용자 정보가 'response' 객체에 포함됨 ``` 3. **커스텀 User Service**: 네이버의 사용자 정보 형식이 구글과 다르므로 `OAuth2UserService`를 커스터마이징: ```java import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Service; import java.util.Map; @Service public class CustomOAuth2UserService extends DefaultOAuth2UserService { @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) { OAuth2User oAuth2User = super.loadUser(userRequest); String registrationId = userRequest.getClientRegistration().getRegistrationId(); if ("naver".equals(registrationId)) { Map response = (Map) oAuth2User.getAttributes().get("response"); return new org.springframework.security.oauth2.core.user.DefaultOAuth2User( oAuth2User.getAuthorities(), response, // 네이버의 사용자 정보 "id" // 고유 식별자 ); } return oAuth2User; } } ``` 4. **SecurityConfig에 등록**: ```java @Configuration public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http, CustomOAuth2UserService customOAuth2UserService) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .oauth2Login(oauth2 -> oauth2 .loginPage("/login") .userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService)) .defaultSuccessUrl("/home") ); return http.build(); } } ``` ##### 커스터마이징 포인트 - **토큰 처리**: `.tokenEndpoint()`로 커스텀 토큰 요청 설정. - **사용자 매핑**: 데이터베이스에 사용자 정보를 저장하거나, 추가 속성을 매핑. - **에러 처리**: `.failureHandler()`로 인증 실패 시 커스텀 로직 추가. ##### 실습 예제 1. 네이버 로그인 버튼 추가: `네이버로 로그인`. 2. 로그인 후 반환된 사용자 정보(이름, 이메일 등)를 화면에 출력. 3. 데이터베이스에 신규 사용자를 등록하는 로직 추가. --- 위 내용은 OAuth2의 기본 개념과 구글 소셜 로그인 구현, 커스텀 OAuth2 클라이언트 설정 방법을 설명했습니다. 추가적인 설정이나 예제가 필요하면 말씀해 주세요!