이번 포스팅은 Oauth2 구현방법 및 흐름을 알아볼려고 한다.
[스프링 시큐리티 Oauth2.0] Oauth2.0 동작방식 (tistory.com)
[스프링 시큐리티 Oauth2.0] Oauth2.0 동작방식
[소개] Oauth2를 사용하기 위해서 Oauth의 흐름을 알아보도록 한다. [Oauth2 사용자] Oauth의 경우 총 4명의 사용자들을 정의 할 수 있다. ● Resource Owner(사용자) : 일반적으로 사용자를 가르키며 소셜 서
thaud153.tistory.com
Oauth2의 전체적인 흐름은 여기 포스팅을 참고하면 될 것 이다.
[Oauth2 구현 방법]
이번 포스팅은 구글과 네이버의 구현방법을 설명할려고 한다.
https://console.cloud.google.com/apis/dashboard
Google 클라우드 플랫폼
로그인 Google 클라우드 플랫폼으로 이동
accounts.google.com
1. 구글 api 콘솔에 들어간다.
2. 동그라미 친 부분을 클릭한다.
3. 새 프로젝트 클릭
4. 만들기 클릭
5. 만들었으면 자신이 만든 프로젝트 클릭 나의 경우 TeamProject01
6. Oauth2 동의 화면 클릭 후 외부 선택 후 만들기
7. 개발자 이메일 및 앱이름 작성(앱이름은 아무거나 작성해도 됨)
8. api 범위 체크 email , Profile 후 업데이트 누르고
저장 및 계속
9.저장 후 계속
10. 사용자 인증정보 클릭 -> 사용자 인증 정보 만들기 -> Oauth2 클라이언트 Id 클릭
1.어플리케이션 유형 -> 웹 어플리케이션
2. 이름 -> 아무거나
3. 승인된 리디렉션(매우 중요) -> localhost:8081/login/oauth2/code/google <- 고정
-> 이 url은 고정이 되어야 한다.
그 이유는 Oauth2의 경우 login/oauth2/code/{RegisterId}가 들어올 경우
Oauth2LoginAuthorzaitonFilter라는 곳에 이 경로에 들어오면 Oauth2 로그인이 되었음을 확인함으로
이 코드는 반드시 저기 동그라미 친 부분과 고정되어야 한다.
ex) 만약 자신이 포트번호를 8080을 쓴다면 localHost8080으로 명시할 것.
나의 경우는 8081을 쓰기 때문에 8081로 적었음을 밝힘.
12. 생성되었다면 클라이언트 Id와 클라이언트 비밀번호가 나옴.
이 클라이언트 ID와 비밀번호를 반드시 기억할 것.
[Section02 네이버 콘솔 만들기]
NAVER Developers
네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음
developers.naver.com
1. 로그인을 한 후 Application -> 내 어플리케이션
2. 내 어플리케이션을 들어간 후 -> 애플리케이션 등록
3. 어플리케이션 이름 등록(아무거나) , 자신이 네이버 api로부터 가지고 오고싶은 정보들을 선택
(나의 경우 회원이름 이메일 , 별명 , 프로필 사진 4개를 가져올 것)
4.네이버의 리다이렉트 주소
이 리다이렉트 주소는 구글과 마찬가지로 고정임.
자신이 포트번호가 8080이라면
http://localhost8080:/login/oauth2/code/naver
이 고정된 주소를 반드시 써야함.
5. 등록이 다 되었다면 클라이언트 아이디랑 시크릿 비밀번호를 반드시 기억할 것.
[Section 03 인텔리제이로 연동하기]
[구글의 경우]
1. 인텔리제이를 킨다.
2. Application properties를 들어간다.
#google
spring.security.oauth2.client.registration.google.client-id=955613786665-irnoig6r5kes6poqupqmpu8v6nug1hgb.apps.googleusercontent.com
spring.security.oauth2.client.registration.google.client-secret=your Secret Code
spring.security.oauth2.client.registration.google.scope=profile,email
자신이 등록했던 클라이언트 id와 클라이언트 비밀번호를 넣고
scope방식은 자신이 등록했던 범위 만큼 넣으면 된다.
나의 경우는 구글에서 email과 profile 두 개를 가져오기로 설정했다.
[네이버의 경우]
#naver
spring.security.oauth2.client.registration.naver.client-id=QS3mYykThvib1IuIyFjZ
spring.security.oauth2.client.registration.naver.client-secret=your Secret Password
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.client-name=naver-clinent-app
spring.security.oauth2.client.registration.naver.redirect-uri=http://localhost:8081/login/oauth2/code/naver
spring.security.oauth2.client.registration.naver.scope=profile,email
-> 구글이랑 다른점?
-> 구글의 경우는 글로벌 기업임으로 api 엔드포인트가 이미 시큐리티에 다 설정되어있다.
하지만 네이버의 경우 글로벌 기업이 아님으로 자신이 직접 엔드포인트 요청을 작성해야 한다.
public enum CommonOAuth2Provider {
GOOGLE {
@Override
public Builder getBuilder(String registrationId) {
ClientRegistration.Builder builder = getBuilder(registrationId,
ClientAuthenticationMethod.CLIENT_SECRET_BASIC, DEFAULT_REDIRECT_URL);
builder.scope("openid", "profile", "email");
builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth");
builder.tokenUri("https://www.googleapis.com/oauth2/v4/token");
builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs");
builder.issuerUri("https://accounts.google.com");
builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
builder.userNameAttributeName(IdTokenClaimNames.SUB);
builder.clientName("Google");
return builder;
}
},
GITHUB {
@Override
public Builder getBuilder(String registrationId) {
ClientRegistration.Builder builder = getBuilder(registrationId,
ClientAuthenticationMethod.CLIENT_SECRET_BASIC, DEFAULT_REDIRECT_URL);
builder.scope("read:user");
builder.authorizationUri("https://github.com/login/oauth/authorize");
builder.tokenUri("https://github.com/login/oauth/access_token");
builder.userInfoUri("https://api.github.com/user");
builder.userNameAttributeName("id");
builder.clientName("GitHub");
return builder;
}
},
FACEBOOK {
@Override
public Builder getBuilder(String registrationId) {
ClientRegistration.Builder builder = getBuilder(registrationId,
ClientAuthenticationMethod.CLIENT_SECRET_POST, DEFAULT_REDIRECT_URL);
builder.scope("public_profile", "email");
builder.authorizationUri("https://www.facebook.com/v2.8/dialog/oauth");
builder.tokenUri("https://graph.facebook.com/v2.8/oauth/access_token");
builder.userInfoUri("https://graph.facebook.com/me?fields=id,name,email");
builder.userNameAttributeName("id");
builder.clientName("Facebook");
return builder;
}
즉 이런식으로 구글 페이스북 깃허브의 경우 스프링에서 설정파일에 엔드포인트 요청이 다 적혀있다.
#naver
spring.security.oauth2.client.registration.naver.client-id=QS3mYykThvib1IuIyFjZ
spring.security.oauth2.client.registration.naver.client-secret=your Secret Password
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.client-name=naver-clinent-app
spring.security.oauth2.client.registration.naver.redirect-uri=http://localhost:8081/login/oauth2/code/naver
spring.security.oauth2.client.registration.naver.scope=profile,email
1. client - id = 클라이언트 아이디는 자신이 네이버 Oauth를 만들었을 때 있는 생성된 id를 넣는다.
2. clinent-secret = 자신이 네이버 oauth2를 만들었을 때 생성된 시크릿 번호를 넣는다.
3. authorization-grant-type = Oauth2 인증 방식을 code방식으로 사용하겠다는 의미이다.
4.clint-name = 사용자에게 Oauth2 인증을 할때 어떤식으로 이름이 보일 것인지 설정 함.
5.redirect -url = 구글이나 네이버 등에서 요청 후 인증 방식을 어디로 보내야할지 정해주는 설정 파일
반드시 naver나 구글에 redircturl로 한 경로를 입력해야한다.(이 경로는 고정임)
6.scope = 네이버 api로 가져올 유저의 정보의 범위를 정하는 설정파일
나의 경우 email과 profile만 가져올 것임.
registation의 정보이다.
즉 여기까지가 우리가 naver나 google에서 필요한 클라이언트 정보를 입력하는 곳
----------------------------------------------------------------------------------
이 부분부터는 본격적으로 네이버에 api의 정보를 넣는 곳이다.
즉 저기 적힌 url경로에 따라 토큰이나 엔드포인트 정보를 가져옴.
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
1. authorization-uri = 네이버의 인증 서버의 주소이다.
2.token - uri = 액세스 토큰을 가져오기 위한 url
3.user-info-url = 액세스 토큰으로 유저의 정보를 가져오기 위한 url 경로이다.
4.user-name-attibutes = 네이버의 경우 Map<String,Object>형식으로 들어오는데
이 key값을 response로 받겠다는 의미이다.
(네이버의 경우 user-info정보가 키 값으로 response로 들어온다.)
(구글의 경우 키 값이 sub)로 들어옴.
5. 이까지 했으면 네이버 , 구글에게 자신의 클라이언트 정보와 , 엔드포인트 요청 url경로까지 다 적어주었다.
[Section 04 구현하기]
1. ProviderUser는 최상위 인터페이스로 NaverUser와 GoogleUser를 묶는 최상위 인터페이스임.
2.Abstractprovider는 구글과 네이버는 공통적으로 들어오는 정보도 있지만 틀리게 들어오는 정보도 있음.
이러한 정보들을 묶어주는 클래스임.
package com.example.oauth2test_01_26.Model;
import org.springframework.security.core.GrantedAuthority;
import java.util.List;
import java.util.Map;
public interface ProviderUser {
String getId();
String getUsername();
String email();
String provider();
List<? extends GrantedAuthority> getAuthorization();
Map<String,Object> getAttributes();
}
1. 최상위 인터페이스 providerUser를 만듬.
2.이 인터페이스에서는 이러한 정보들을 가져올 것 임.
package com.example.oauth2test_01_26.Model;
import com.example.oauth2test_01_26.Converter.ConverterAttributes;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.user.OAuth2User;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public abstract class AbstractProvider implements ProviderUser{
private ClientRegistration registration;
private OAuth2User user;
private Map<String,Object> attributes;
public AbstractProvider(ClientRegistration registration, OAuth2User user, Map<String,Object> attributes) {
this.registration = registration;
this.user = user;
this.attributes = attributes;
}
@Override
public String getUsername() {
return null;
}
@Override
public String email() {
return attributes.get("email").toString();
}
@Override
public String provider() {
return registration.getRegistrationId();
}
@Override
public List<? extends GrantedAuthority> getAuthorization() {
return user.getAuthorities().stream().map(auth -> new SimpleGrantedAuthority(auth.getAuthority())).collect(Collectors.toList());
}
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
}
2.이 추상클래스에서는 username , email , provider , Authorization , getAttribute등을 가져오는 추상클래스임
이 메서드들은 네이버와 유저 구글이 공통으로 들어가는 부분이기에 추상클래스에서 구현
[구글 클래스]
package com.example.oauth2test_01_26.Model;
import com.example.oauth2test_01_26.Converter.ConverterAttributes;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.user.OAuth2User;
public class GoogleUser extends AbstractProvider{
public GoogleUser(ClientRegistration registration, OAuth2User user, ConverterAttributes converterAttributes){
super(registration,user,converterAttributes.getGoogleMap());
}
@Override
public String getId() {
return getAttributes().get("sub").toString();
}
}
1. 구글 클래스에서는 id의 키값이 sub로 들어오기 때문에 네이버랑 다름.
그렇기 떄문에 id메서드를 따로 구현해서 꺼냄.
[네이버 클래스]
package com.example.oauth2test_01_26.Model;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.user.OAuth2User;
import java.util.Map;
public class NaverUser extends AbstractProvider{
public NaverUser(ClientRegistration registration, OAuth2User user, Map<String, Object> attributes) {
super(registration, user, attributes);
}
@Override
public String getId() {
return getAttributes().get("id").toString();
}
@Override
public String getUsername() {
return super.getAttributes().get("nickname").toString();
}
}
1. 네이버의 클래스의 경우 id를 꺼내는 키값이 id임.
2.네이버에서는 닉네임도 들어옴. 그렇기 때문에 nickName으로 꺼낼 시
네이버에 저장된 닉네임도 가져올 수 있음.
[Section 04 구글과 네이버의 컨버터 만들기 ]
1. ProviderUserRequest
만약 스프링에서 Oauth2 유저정보와 ClientRegistration을 가져올 시
제일먼저 ProviderUserRequest의 저장 해서 이 객체에 있는 정보들로
구글과 네이버등의 유저정보들을 컨버팅 할 것 임.
2. AbstractDelegatingOauth2Converter
이 클래스는 권한을 부여하는 추상 클래스로써
구글이나 네이버의 oauth2 인증방식이 들어왔을 시 이 객체를 거쳐
이 객체가 적절한 판단을 한 후 NaverUserConverter 혹은 GoogleUserConverter에 권한을 위임할 것.
3.NaverUserConverter
네이버 Oauth2로 들어올 시 네이버의 정보를 컨버팅해서 NaverUser에 담을 것임.
4.GoogleUserConver
구글 Oauth2로 들어올 시 구글의 정보를 컨버팅해서 GoogleUser의 담을 것 임
package com.example.oauth2test_01_26.Converter;
public interface ProviderOauth2Converter <T,R>{
R converter(T t);
}
1.최상위 인터페이스를 제네릭으로 선언함.
package com.example.oauth2test_01_26.Converter;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.user.OAuth2User;
public record ProviderUserRequest(ClientRegistration registration, OAuth2User user) {
}
2.record형식으로 선언되었으며 생성자에 ClientRegistration과 Oauth2를 넣으면
자동으로 필드객체에 ClientRegstration과 Oauth2의 주소정보 (개체 정보)를 넣는다.
package com.example.oauth2test_01_26.Converter;
import com.example.oauth2test_01_26.Model.GoogleUser;
import com.example.oauth2test_01_26.Model.ProviderUser;
import java.util.Arrays;
import java.util.List;
public abstract class AbstractDelegatingOauth2Converter implements ProviderOauth2Converter<ProviderUserRequest, ProviderUser>{
private List<? extends ProviderOauth2Converter> list;
//초기화와 동시에 List객체에 구글 컨버터와 네이버의 컨버터를 개체를 저장함.
public AbstractDelegatingOauth2Converter(){
List<? extends ProviderOauth2Converter> list = Arrays.asList(new GoogleUserConverter(),new NaverUserConverter());
this.list = list;
}
@Override
public ProviderUser converter(ProviderUserRequest request) {
//이 객체를 저장해서 이 개체를 컨버터 하면서 컨버팅(구글 유저 -> 구글 컨버팅 , 네이버 유저 -> 네이버 컨버팅)
//네이버에 유저가 들어올 시 -> 네이버 컨버팅 -> NaverUser객체를 뱉음.
//구글에 유저가 들어올 시 -> 구글 컨버팅 -> GoogleUser 객체를 뱉음
for (ProviderOauth2Converter providerOauth2Converter : list) {
ProviderUser converter = (ProviderUser) providerOauth2Converter.converter(request);
if(converter != null) return converter;
}
return null;
}
}
2.AbstractDelegatingOauth2Converter
권한을 위임하는 클래스며
구글로 유저가 들어오면 구글 컨버팅이 동작하게 됨.
네이버로 유저가 들어오면 네이버로 컨버팅이 동작하게 됨.
package com.example.oauth2test_01_26.Converter;
import lombok.Builder;
import lombok.Getter;
import org.springframework.security.oauth2.core.user.OAuth2User;
import java.util.Map;
@Builder
@Getter
public class ConverterAttributes {
private final Map<String,Object> googleMap;
private final Map<String,Object> naverMap;
public static ConverterAttributes GoogleAttributesConverter(OAuth2User user){
return ConverterAttributes.builder().googleMap(user.getAttributes()).build();
}
public static ConverterAttributes NaverAttributesConverter(OAuth2User user){
Map<String, Object> response = (Map<String, Object>) user.getAttributes().get("response");
return ConverterAttributes.builder().naverMap(response).build();
}
}
3. 네이버나 구글의 정보가 들어왔을 시 Map형태에서 빼서 가공된 데이터를
전역변수 Map에 넣어주는 역활을 함.
구글의 경우 sub로 들어오고
네이버의 경우 response의 2단으로 Map형태로 들어오기 때문에
키로 2번을 뺴줘야 함.
package com.example.oauth2test_01_26.Converter;
import com.example.oauth2test_01_26.Model.GoogleUser;
import com.example.oauth2test_01_26.Model.ProviderUser;
public class GoogleUserConverter implements ProviderOauth2Converter<ProviderUserRequest, ProviderUser>{
@Override
public ProviderUser converter(ProviderUserRequest request) {
//프로바이더정보가 구글이 아니면 네이버이기 때문에 return null을 줌
if(!request.registration().getRegistrationId().equals("google")) return null;
ConverterAttributes converterAttributes = ConverterAttributes.GoogleAttributesConverter(request.user());
//유저가 구글로 들어왔을 때 구글의 정보를 GoogleUser로 리턴
return new GoogleUser(request.registration(), request.user(),converterAttributes);
}
}
package com.example.oauth2test_01_26.Converter;
import com.example.oauth2test_01_26.Model.NaverUser;
import com.example.oauth2test_01_26.Model.ProviderUser;
public class NaverUserConverter implements ProviderOauth2Converter<ProviderUserRequest, ProviderUser>{
@Override
public ProviderUser converter(ProviderUserRequest request) {
//Provider정보가 네이버가 아니면 구글이기때문에 return null
if(!request.registration().getRegistrationId().equals("naver")) return null;
ConverterAttributes converterAttributes = ConverterAttributes.NaverAttributesConverter(request.user());
//유저가 네이버임이 확인되면 NaverUser에서 네이버(유저정보) 정보로 넣음
return new NaverUser(request.registration(),request.user(),converterAttributes.getNaverMap());
}
}
package com.example.oauth2test_01_26.Service;
import com.example.oauth2test_01_26.Table.UserInformation;
import com.nimbusds.openid.connect.sdk.claims.UserInfo;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User;
import java.util.Collection;
import java.util.Map;
@Data
public class UserService implements UserDetails, OAuth2User {
private UserInformation information;
public UserService(UserInformation information) {
this.information = information;
}
@Override
public <A> A getAttribute(String name) {
return OAuth2User.super.getAttribute(name);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return information.getAuthorities();
}
@Override
public String getPassword() {
return information.getPassWord();
}
@Override
public String getUsername() {
return information.getUserNickName();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public Map<String, Object> getAttributes() {
return information.getProviderUser().getAttributes();
}
@Override
public String getName() {
return information.getUserNickName();
}
}
package com.example.oauth2test_01_26.Service;
import com.example.oauth2test_01_26.Converter.ProviderOauth2Converter;
import com.example.oauth2test_01_26.Converter.ProviderUserRequest;
import com.example.oauth2test_01_26.Model.ProviderUser;
import com.example.oauth2test_01_26.Repository.UserRepository;
import com.example.oauth2test_01_26.Table.UserEntity;
import com.example.oauth2test_01_26.Table.UserInformation;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.security.oauth2.core.user.OAuth2User;
@Getter
@RequiredArgsConstructor
public abstract class AbstractOauth2UserService {
private final UserRepository repository;
private final ProviderOauth2Converter<ProviderUserRequest, ProviderUser> converter;
protected ProviderUser Converter(ProviderUserRequest request){
ProviderUser converter1 = converter.converter(request);
return converter1;
}
protected void register(ProviderUser user){
UserEntity build = UserEntity.builder().provider(user.provider())
.username(user.getUsername())
.email(user.email())
.build();
repository.save(build);
}
protected UserInformation TransferUserInformation(ProviderUser user){
if(user.provider().equals("naver")){
return UserInformation.builder().userNickName(user.getUsername())
.providerUser(user).passWord(null)
.email(user.email())
.authorities(user.getAuthorization())
.build();
}else {
return UserInformation.builder().userNickName("닉네임 없음")
.providerUser(user).passWord(null)
.email(user.email())
.authorities(user.getAuthorization())
.build();
}
}
}
1.TransferUserInofrmation부분은 유저의 정보를 시큐리티에서 꺼낼 때
일반 폼로그인 유저와 , Oauth 유저의 정보를 통합하기 위해 UserInfomation클래스에 넣어서
함께 묶어서 쓰기위함이다.
package com.example.oauth2test_01_26.Table;
import com.example.oauth2test_01_26.Converter.ProviderUserRequest;
import com.example.oauth2test_01_26.Model.ProviderUser;
import lombok.Builder;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import java.util.List;
@Data
public class UserInformation {
private String userNickName;
private String passWord;
private List<? extends GrantedAuthority> authorities;
private String email;
private ProviderUser providerUser;
@Builder
public UserInformation( String userNickName, String passWord, List<? extends GrantedAuthority> authorities, String email, ProviderUser providerUser) {
this.userNickName = userNickName;
this.passWord = passWord;
this.authorities = authorities;
this.email = email;
this.providerUser = providerUser;
}
}
이 부분에 UserInformation부분이며
1. 폼로그인 방식과 Oauth2의 유저 정보를 함께 공유하기 위해 사용되는 클래스임
이렇게 하지 않으면 폼로그인과 Oauth2유저가 묶이지 않아서
폼로그인 유저가 들어왔을때 Oauth2과 관련된 정보를 꺼낸다면 NPE가 뜸
package com.example.oauth2test_01_26.Service;
import com.example.oauth2test_01_26.Converter.ProviderOauth2Converter;
import com.example.oauth2test_01_26.Converter.ProviderUserRequest;
import com.example.oauth2test_01_26.Model.ProviderUser;
import com.example.oauth2test_01_26.Repository.UserRepository;
import com.example.oauth2test_01_26.Table.UserInformation;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
@Service
public class CustomOauth2UserService extends AbstractOauth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
public CustomOauth2UserService(UserRepository repository, ProviderOauth2Converter<ProviderUserRequest, ProviderUser> converter) {
super(repository, converter);
}
@Override
//여기에 들어오는 userRequest 액세스토큰과 , 코드등이 들어있음 유저 정보는 X
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
ClientRegistration clientRegistration = userRequest.getClientRegistration();
OAuth2UserService<OAuth2UserRequest,OAuth2User> oAuth2UserService
= new DefaultOAuth2UserService();
//이 메서드 호출로 유저의 정보를 가져옴.
//이 메서드 호출로 oauth2User에는 유저 정보가 들어있음.
OAuth2User oAuth2User = oAuth2UserService.loadUser(userRequest);
//우리가 만든 ProviderUserRequest 이안에 Client와 Oauth2(유저 정보)등을 저장함.
ProviderUserRequest providerUserRequest = new ProviderUserRequest(clientRegistration, oAuth2User);
//각 Oauth2맞는 값들은 변환
ProviderUser converter = super.Converter(providerUserRequest);
super.register(converter);
//oauth2와 폼데이터 방식(자체 회원가입)을 함께 묶어서 사용하기 위한 로직
UserInformation userInformation = super.TransferUserInformation(converter);
//이 함께 묶은 정보를 UserService에 저장함
UserService userService = new UserService(userInformation);
return userService;
}
}
여기까지 정리했다면 이제 Config를 만들어줘야한다.
-> 그이유는 ProviderOauth2Converter의 최상위 인터페이스가 있는데
이 인터페이스 안에 AbstractDelegatingOauth2Converter부분을 의존성을 주입시켜줘야한다.
그래야만 ProviderOauth2Converter의 Converter가 실행되었을 때
AbstractDelegatingOauth2Converter이 개체가 실행된다.
package com.example.oauth2test_01_26;
import com.example.oauth2test_01_26.Converter.AbstractDelegatingOauth2Converter;
import com.example.oauth2test_01_26.Converter.ProviderOauth2Converter;
import com.example.oauth2test_01_26.Converter.ProviderUserRequest;
import com.example.oauth2test_01_26.Model.ProviderUser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@EnableWebSecurity
@Configuration
public class SecurityConfig {
@Bean
public ProviderOauth2Converter<ProviderUserRequest, ProviderUser> converter(){
return new AbstractDelegatingOauth2Converter() {
@Override
public ProviderUser converter(ProviderUserRequest request) {
return super.converter(request);
}
};
}
}
'스프링 시큐리티 -세션 > Oauth2.0' 카테고리의 다른 글
Oauth2 필터체인 동작 방식 흐름 및 이해 (1) | 2024.02.05 |
---|---|
[스프링 시큐리티 Oauth2.0] Oauth2.0 동작방식 (0) | 2024.01.19 |