OAuth2
기본 설정
- spring boot 2.0.0
- spring security 5.0.0
Dependency
/*oauth2 를 위해 아래 2개의 dependencies 필요.*/
compile ('org.springframework.security:spring-security-oauth2-client')
compile ('org.springframework.security:spring-security-oauth2-jose')
Configuration
- application.yml
spring:
security:
oauth2:
client:
registration:
google:
client-id: 283082856244-lfjqd0vbudb2c1fvolgl6d5a444fc3im.apps.googleusercontent.com
client-secret: 4w6UG90Rod6rzPGwax_LLwDQ //랜덤으로 적은 것임
facebook:
client-id: 429830609684099
client-secret: 2940f70d34e1ca670b5cb326515e7a69 //랜덤으로 적은 것임
SecurityConfig
아래 설정대로라면, /secret/** 또는 /userinfo 접속시 oauth2Login 페이지로 redirect 하게 된다.
package com.example.demo.config;
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.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
public class SecurityConfig {
@Configuration
public static class WebBaseSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secret/**", "/userinfo").authenticated()
.anyRequest().permitAll()
.and()
.oauth2Login()
.loginPage("/signIn");
}
}
}
redirect 된 페이지에서는 /oauth2/authorization/{registrationId} 로 redirect 하는 <a> 태그가 있으면 된다. 클릭시 해당 oauth2 provider 의 로그인 페이지로 간다. (/oauth2/authorization/google)
웹에서
- controller
- 파라미터로 OAuth2AuthenticationToken authentication 를 받는다.
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
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.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 java.util.Collections;
import java.util.Map;
@Controller
public class HomeController {
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@GetMapping("/")
public String index() {
return "index";
}
@RequestMapping("/secret")
public String oauth2SignIn(Model model, OAuth2AuthenticationToken authentication) {
OAuth2AuthorizedClient authorizedClient = this.getAuthorizedClient(authentication);
model.addAttribute("userName", authentication.getName()); //id
model.addAttribute("clientName", authorizedClient.getClientRegistration().getClientName()); //google, facebook 등
return "secret";
}
@RequestMapping("/userinfo")
public String userInfo(Model model, OAuth2AuthenticationToken authentication) {
OAuth2AuthorizedClient authorizedClient = this.getAuthorizedClient(authentication);
model.addAttribute("userAttributes", this.oauth2UserAttributes(authorizedClient));
return "userInfo";
}
private OAuth2AuthorizedClient getAuthorizedClient(OAuth2AuthenticationToken authentication) {
return this.authorizedClientService.loadAuthorizedClient(
authentication.getAuthorizedClientRegistrationId( ), authentication.getName());
}
/**
* @param authorizedClient
* @return -
* * @examples
* * * @google
* * * * sub : 110233381282913480987 => authentication.getName() 과 같다.
* * * * name : 길병찬[소프트웨어학부] => given_name + " " + family_name 이다.
* * * * given_name : 길병찬[소프트웨어학부]
* * * * family_name :
* * * * picture : https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/photo.jpg
* * * * email : [email protected]
* * * * email_verified : true
* * * * locale : ko
* * * * hd : kookmin.ac.kr => 이메일 도메인을 의미한다.
*
* * * @facebook
* * * * name : 길병찬
* * * * id : 1236697273129887 => authentication.getName() 과 같다.
*/
private Map oauth2UserAttributes(OAuth2AuthorizedClient authorizedClient) {
String userInfoEndpointUri = authorizedClient.getClientRegistration()
.getProviderDetails().getUserInfoEndpoint().getUri();
Map userAttributes = Collections.emptyMap();
if (!StringUtils.isEmpty(userInfoEndpointUri)) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + authorizedClient.getAccessToken()
.getTokenValue());
String body = "";
HttpEntity entity = new HttpEntity(body, headers);
ResponseEntity<Map> response = restTemplate
.exchange(userInfoEndpointUri, HttpMethod.GET, entity, Map.class);
userAttributes = response.getBody();
}
return userAttributes;
}
@GetMapping("/signIn")
public String signIn() {
return "signIn";
}
}
REST 하게
앱에서
Custom Login Page
(SecurityConfig 에서 설정한 loginPage 의 uri를 Controller 에서 @GetMapping
하는 것이 필요하다.)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>로그인</h1>
<a th:href="@{/oauth2/authorization/google}">sign in with Google</a>
<br>
<a th:href="@{/oauth2/authorization/facebook}">sign in with Facebook</a>
</body>
</html>
DB 기반 로그인과 같이하기
Role
google, facebook, github, okta 이외의 provider
- 카카오