인터넷에 나와있는 SpringBoot + 페이스북 연동 은 1.x 버전이라 안됩니다.
그래서 Spring Security Oauth2 를 이용해서 로그인하는 방법에 대해 다루를 예정입니다.
시작하기 전에 페이스북 디벨로퍼에 접속하여 새로운 App을 생성합니다.
생성할 때, 'Facebook 로그인' 을 설정해 둡니다.
https://developers.facebook.com/?locale=ko_KR
여기서 사용되는 예제에서는 샘플 앱을 만들었으니 코드를 그대로 사용하셔도 됩니다.
구성은 다음과 같습니다.
- Spring Boot 2.x
- thymeleaf
- Spring security
- Spring security oauth2
1. Gradle 설정
compile('org.springframework.boot:spring-boot-starter-thymeleaf') compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') compileOnly('org.projectlombok:lombok') compile('org.springframework.boot:spring-boot-starter-security') compile('org.springframework.security.oauth:spring-security-oauth2:2.3.3.RELEASE') compile('org.springframework.security.oauth:spring-security-oauth2') compile('org.springframework.security:spring-security-oauth2-client')
2. application.yml 설정
프로퍼티 파일을 yml 로 수정한 것입니다.
spring: security: oauth2: client: registration: # 페이스북 앱 정보 facebook: client-id: 681655205504975 client-secret: 7a37be5aa42a483202c94744a5747065 # 구글 앱 정보 google: client-id: test client-secret: test_secret # 소셜 로그인 사용할 SNS 종류. 이번 샘플에는 구글 연동을 하지 않았습니다. spring.social.auths: facebook,google
3. Spring Security 설정
import lombok.extern.java.Log; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; 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.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.oauth2.client.CommonOAuth2Provider; import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @Log @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/oauth_login").permitAll() .antMatchers("/**").permitAll() .and() .oauth2Login() .loginPage("/oauth/login.html") .clientRegistrationRepository(clientRegistrationRepository()) .authorizedClientService(authorizedClientService()) .defaultSuccessUrl("/oauth/login_success") .failureUrl("/oauth/login_fail") ; } /** * OAuth 로 페이스북 연동 만드는 중. * 참조사이트: http://www.baeldung.com/spring-security-5-oauth2-login */ private static String CLIENT_PROPERTY_KEY = "spring.security.oauth2.client.registration."; private static Listclients; @Value("${spring.social.auths}") String socialAuths; @Autowired private Environment env; @Bean public ClientRegistrationRepository clientRegistrationRepository() { clients = Arrays.asList(socialAuths.split(",")); List registrations = clients.stream() .map(c -> getRegistration(c)) .filter(registration -> registration != null) .collect(Collectors.toList()); return new InMemoryClientRegistrationRepository(registrations); } private ClientRegistration getRegistration(String client) { String clientId = env.getProperty( CLIENT_PROPERTY_KEY + client + ".client-id"); if (clientId == null) { return null; } String clientSecret = env.getProperty( CLIENT_PROPERTY_KEY + client + ".client-secret"); if (client.equals("google")) { return CommonOAuth2Provider.GOOGLE.getBuilder(client) .clientId(clientId).clientSecret(clientSecret).build(); } if (client.equals("facebook")) { return CommonOAuth2Provider.FACEBOOK.getBuilder(client) .clientId(clientId).clientSecret(clientSecret).build(); } return null; } @Bean public OAuth2AuthorizedClientService authorizedClientService(){ return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository()); } }
4. Oauth2 로그인 컨트롤러 생성
LoginOauth2Controller 파일을 생성하고 아래의 코드를 추가합니다.
그리고 샘플이기 때문에 root path("/") 도 추가해 두겠습니다.
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ResolvableType; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import java.util.HashMap; import java.util.Map; /** * 소셜 로그인 담당 컨트롤러 */ @Controller public class LoginOauth2Controller { @RequestMapping(path={"/", "/main"}) public String main(){ return "main"; } // 기본 URL 설정 private static String authorizationRequestBaseUri = "/oauth2/authorization"; Mapoauth2AuthenticationUrls = new HashMap<>(); @Autowired private ClientRegistrationRepository clientRegistrationRepository; // 로그인 시도 이후 받아온 정보 @Autowired private OAuth2AuthorizedClientService authorizedClientService; // 로그인 화면 @GetMapping("/oauth/login") public String login(Model model) { Iterable clientRegistrations = null; ResolvableType type = ResolvableType.forInstance(clientRegistrationRepository) .as(Iterable.class); if (type != ResolvableType.NONE && ClientRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) { clientRegistrations = (Iterable ) clientRegistrationRepository; } clientRegistrations.forEach(registration -> oauth2AuthenticationUrls.put(registration.getClientName(), authorizationRequestBaseUri + "/" + registration.getRegistrationId())); model.addAttribute("urls", oauth2AuthenticationUrls); return "oauth/login"; } // 로그인 성공 후 @GetMapping("/oauth/login_success") public String login_success(Model model, OAuth2AuthenticationToken authentication){ OAuth2AuthorizedClient client = authorizedClientService .loadAuthorizedClient( authentication.getAuthorizedClientRegistrationId(), authentication.getName() ); String userInfoEndpointUri = client.getClientRegistration() .getProviderDetails().getUserInfoEndpoint().getUri(); if (!StringUtils.isEmpty(userInfoEndpointUri)) { RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + client.getAccessToken().getTokenValue()); HttpEntity entity = new HttpEntity(headers); ResponseEntity
5. HTML 파일을 생성합니다.
thymeleaf 를 사용하기 때문에 resources/templates 폴더 아래에 두어야 합니다.
5-1. main.html 파일 생성
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="/assets/img/favicon.ico">
<meta name="description" content="">
<meta name="author" content="">
</head>
<body>
메인페이지 입니다.
<br>
<a href="/oauth/login">소셜로그인 페이지 이동</a>
</body>
</html>
5-2. oauth/login.html 파일 생성
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="/assets/img/favicon.ico">
<meta name="description" content="">
<meta name="author" content="">
</head>
<body>
<p>소셜 로그인 화면</p>
<h3>Login with:</h3>
<p th:each="url : ${urls}">
<a th:text="${url.key}" th:href="${url.value}">Client</a>
</p>
<!--<br>-->
<!--<p>페이스북 로그인</p>-->
<!--<a href="/oauth2/authorization/facebook" target="_blank">Facebook</a>-->
</body>
</html>
5-3. oauth/login_success.html 파일 생성
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="/assets/img/favicon.ico">
<meta name="description" content="">
<meta name="author" content="">
</head>
<body>
<p>소셜 로그인 성공</p>
<p>이름: <span th:text="${userInfo.name}"></span></p>
<p>이메일: <span th:text="${userInfo.email}"></span></p>
<br>
<a href="/">Go Home</a>
</body>
</body>
</html>
실행해서
http://localhost:8080/ 를 접속하여 링크를 따라가면 됩니다.
구글 버튼은 활성화 되어있지만 작동하지 않습니다.
관련 소스는 깃헙에 올려두었습니다.
https://github.com/lemontia/SpringBoot2_oauth2
'공부 > 프로그래밍' 카테고리의 다른 글
[SpringBoot] Cloud Config Server-Github에 설정파일 두고 사용하기 (0) | 2018.07.10 |
---|---|
[SpringBoot 2.x] 회원가입 할 때 이미 가입한 회원이면 로그인 + Auth 하기. (0) | 2018.07.09 |
[SpringBoot] (Spring Security) 로그인 후 호출했던 이전 페이지로 이동하기 (0) | 2018.07.06 |
[SpringBoot] (Spring Security) 로그인 시 추가정보 User 에 담기 (0) | 2018.07.05 |
[SpringBoot] JPA 설정 및 테스트 (0) | 2018.07.04 |
댓글