on
12. Naver, Google을 이용하여 oauth인증하기
12. Naver, Google을 이용하여 oauth인증하기
https://developers.naver.com/apps
해당 사이트에 들어가 원하는 api를 선택한다. 지금은 테스트이기 떄문에 회원이름과 이메일의 정보를 받아오도록 하겠다.
주소를 입력하고 받아올 정보를 넘길곳을 지정해준다.
https://console.developers.google.com/
새프로젝트로 가기를 선택하면이동되는 창
새 프로젝트 만들기를 선택 후 이름을 넣어준다.
위에 있는 링크를 다시한번 들어가게 되면 왼쪽에 아래의 사진과 같은 메뉴를 볼 수 있다.
인증정보 메뉴를 선택 후 사용자 인증정보 만들기를 누른다. 그 후 OAuth 클라이언트 ID 만들기를 누르고 동의화면만들기를 누른다. 외부 선택 후 만들기
다시 사용자 인증정보 만들기에 들어가 OAuth 클라이언트 ID 만들기를 누르고 웹 어플리케이션을 선택한다.
URL https://localhost:8080 승인된 리다이렉션 URL http://localhost:8080/login/oauth2/code/google
생성된 아이디와 비밀번호를 따로 적어두어야 한다.
프로젝트 생성
Loombok에 에러가 날 가능성이 높기 때문에 이번에도 start.spring.io를 통해 프로젝트를 만들었다.
start.spring.io
hello.html생성(인증성공 후 페이지)
Insert title here 인증 성공 User name : Authorities : Logout
API를 통한 보안인증은 가져온 Email, 이름을 attribute에 집어넣을 예정이다.
home.htm
Insert title here Home Page 로그인
login.html생성
Insert title here $(function(){ $('a').bind("click", function(){ location.href = "/oauth2/authorization/" + $(this).attr("data-social"); }); }); Login Page Google Naver
Jquery를 이용하여 구글을 클릭시 구글로 네이버로 클릭시 네이버로 로그인가능하게 하는 창으로 넘어가게한다.
loginFailure.html생성(로그인 실패)
Insert title here 인증 실패 Login Again
logout.html생성
Document Custom Logout Page Logout Logout
application.properties
spring.thymeleaf.cache=false spring.security.oauth2.client.registration.google.client-id=클라이언트 아이디 spring.security.oauth2.client.registration.google.client-secret= 비밀번호 spring.security.oauth2.client.registration.google.scope=profile,email spring.security.oauth2.client.registration.naver.client-id=클라이언트 아이디 spring.security.oauth2.client.registration.naver.client-secret=비밀번호 spring.security.oauth2.client.registration.naver.redirect-uri={baseUrl}/{action}/oauth2/code/{registrationId} spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code spring.security.oauth2.client.registration.naver.scope=name,email spring.security.oauth2.client.registration.naver.client-name=Naver spring.security.oauth2.client.provider.naver.authorization-uri=https://nid.naver.com/oauth2.0/authorize spring.security.oauth2.client.provider.naver.token-uri=https://nid.naver.com/oauth2.0/token spring.security.oauth2.client.provider.naver.user-info-uri=https://openapi.naver.com/v1/nid/me spring.security.oauth2.client.provider.naver.user-name-attribute=response
모든설정은 application.properties에서 한다.
기본적으로 클라이언트 아이디와 비밀번호가 필요한데 oauth인증시에는 추가적인 정보가 더 들어간다.
Naver제일 하단에 보면 response가 붙는것을 확인할 수 있는데 갔다올 때 json형태로 오는 키값이다.
OAuth2Controller.java생성
@Slf4j @Controller public class OAuth2Controller { @GetMapping({ "", "/" }) public String getAuthorizationMessage() { return "home"; } @GetMapping("/login") public String login() { return "login"; } @GetMapping({ "/loginSuccess", "/hello" }) public String loginSuccess(Principal principal, Model model) { return "hello"; } @GetMapping("/loginFailure") public String loginFailure() { return "loginFailure"; } @GetMapping("/logout") public void logout() { log.info("called Logout page"); } }
OAuthAttributes.java생성
@Slf4j @Getter public class OAuthAttributes { private Map attributes; private String nameAttributeKey; private String name; private String email; @Builder public OAuthAttributes(Map attributes, String nameAttributeKey, String name, String email) { this.attributes = attributes; this.nameAttributeKey = nameAttributeKey; this.name = name; this.email = email; } public static OAuthAttributes of(String registrationId, String userNameAttributeName, Map attributes) { if ("naver".equals(registrationId)) { return ofNaver("id", attributes); } return ofGoogle(userNameAttributeName, attributes); } private static OAuthAttributes ofGoogle(String userNameAttributeName, Map attributes) { return OAuthAttributes.builder().name((String) attributes.get("name")).email((String) attributes.get("email")) .attributes(attributes).nameAttributeKey(userNameAttributeName).build(); } private static OAuthAttributes ofNaver(String userNameAttributeName, Map attributes) { Map response = (Map) attributes.get("response"); return OAuthAttributes.builder().email((String) response.get("email")).name((String) response.get("name")) .attributes(response).nameAttributeKey(userNameAttributeName).build(); } }
위에서 언급했다시피 Attribute안에 정보(Email, 이름)를 집어넣는다.
builder라는 Annotaion을 통해 Attribute를 Setting을 한다.
네이버를 요청했다면 네이버method로 가고 Google을 요청했다면 Google로 이동하게한다.
Application.properties에서 언급했던 Response라는 키값을 이용하여 정보를 가져온다.
CustomOAuth2UserService.java
public class CustomOAuth2UserService implements OAuth2UserService { @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { OAuth2UserService delegate = new DefaultOAuth2UserService(); // UserService를 하나 만든다. OAuth2User oAuth2User = delegate.loadUser(userRequest); // 요청 request에 의해 유저를 만들면 이름과 이메일이 들어온다. String registrationId = userRequest.getClientRegistration().getRegistrationId(); String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint() //Endpoint() : 정보가 저장되어있는 곳이다. .getUserNameAttributeName(); OAuthAttributes attributes = OAuthAttributes.of(registrationId, userNameAttributeName, oAuth2User.getAttributes()); // 네이버 또는 구글의 인증을 가져온다 Set authorities = new LinkedHashSet<>(); authorities.add(new OAuth2UserAuthority(attributes.getAttributes())); //정보 담기 OAuth2AccessToken token = userRequest.getAccessToken(); // AccessToken() = principle for (String authority : token.getScopes()) { authorities.add(new SimpleGrantedAuthority("SCOPE_" + authority)); // Role_도 있지만 SCOPE_도 있다. } return new DefaultOAuth2User(authorities, attributes.getAttributes(), attributes.getNameAttributeKey()); } }
: 받아오는 값이 naver, Google요청하느냐에 따라 값이 변하게 map으로 처리한다
OAuth2UserService interface를 상속받으며 OAuth2User 값을 리턴한다.
SocialType enum 생성
public enum SocialType { FACEBOOK("facebook"), GOOGLE("google"), KAKAO("kakao"), NAVER("naver"); //반드시 enum은 상수를 먼저 써야한다. private final String ROLE_PREFIX = "ROLE_"; private String name; SocialType(String name) { //앞에 public을 사용하면안된다. this.name = name; } public String getRoleType() { return ROLE_PREFIX + name.toUpperCase(); } public String getValue() { return name; } public boolean isEquals(String authority) { return this.getRoleType().equals(authority); } }
SecurityConfig.java 생성
package com.example.oauth2.security; import static com.example.oauth2.security.SocialType.FACEBOOK; import static com.example.oauth2.security.SocialType.GOOGLE; import static com.example.oauth2.security.SocialType.KAKAO; import static com.example.oauth2.security.SocialType.NAVER; 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.web.authentication.LoginUrlAuthenticationEntryPoint; import com.example.service.CustomOAuth2UserService; import lombok.extern.slf4j.Slf4j; @Slf4j @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws java.lang.Exception{ http.authorizeRequests().antMatchers("/", "/oauth2/**", "/login/**", "/css/**","/images/**", "/js/**", "/console/**","/favicon.ico/**") .permitAll() .antMatchers("/facebook").hasAuthority(FACEBOOK.getRoleType()) .antMatchers("/google").hasAuthority(GOOGLE.getRoleType()) .antMatchers("/kakao").hasAuthority(KAKAO.getRoleType()) .antMatchers("/naver").hasAuthority(NAVER.getRoleType()) .anyRequest().authenticated() .and() .oauth2Login() //oauth2인증 받아오기 .userInfoEndpoint().userService(new CustomOAuth2UserService()) .and() .defaultSuccessUrl("/loginSuccess") .failureUrl("/loginFailure") .and() .exceptionHandling() .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")); // http.logout().logoutUrl("/logout").invalidateHttpSession(true).logoutSuccessUrl("/login"); //로그아웃하면 다시 로그인 창으로 가게 설정한다. } }
WebSecurityConfigurerAdapter을 상속받는다.
스태틱 import가 잘 안들어오기 때문에 import문을 따로 작성해준다(KAKAO, GOOGLE, NAVER, FACEBOOK).
from http://wonho.tistory.com/22 by ccl(A) rewrite - 2021-12-12 23:27:08