OAuth2User
。OAuth의 UserDetails 역할을 수행하는Spring Security Core Interface
。OAuth Client가 요청한사용자정보에 대해OAuth Provider에서 응답한사용자정보를 포항한Oauth2User생성
▶ 기존DB에서 저장된사용자정보를 가져와서 생성되는UserDetails와 차이가 존재
。OAuth2UserService의loadUser(OAuth2UserRequest userRequest)에 의해 생성
커스텀 OAuth2User 구현체정의
。@Getter를 통해구현메서드:email / name / attributes의getter를 축약
。DTO로서의필드및OAuth Provider에서 제공되는사용자정보에 해당하는필드(attributes)를 정의해야한다.@Accessors(chain = true) @Getter public class CurretUser implements OAuth2User { private String email; private String name; private Map<String,Object> attributes; @Setter private String role; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return List.of( new SimpleGrantedAuthority(role) ); } @Builder public CurretUser(String email, String name, Map<String, Object> attributes){ this.email = email; this.name = name; this.attributes = attributes; } public static CurrentUser from(CurretUser user){ if(user == null) throw new IllegalArgumentException("MEMBER_NOT_FOUND"); return CurrentUser.builder() .name(user.getName()) .email(user.getEmail()) .build() // MemberDetails 내 @Accessor 을 통해 // setter에서 객체를 반환하도록 설정. .setId(user.getId()) .setRole(user.getRole()); } }
attributes:
。OAuth Provicer가Resource Server에서 반환한사용자정보 데이터를 저장하는Map 자료구조 field
▶Map <Key,Value> 객체로 반환
ex )OAuth Provider : Goole인 경우클라이언트에서사용자정보를이름, 이메일에 대해권한을 부여받은 경우사용자 정보는 다음처럼 반환.{ "sub": "123456", "email": "test@gmail.com", "name": "kim" }▶
Map 객체에서Map객체.get("key명")을 통해 가져와서 활용
OAuth2UserService:
。OAuth 2.0의 UserDetailsService 역할을 수행하는인터페이스
。권한부여승인코드를 통해 획득한Access Token을 통해OAuth Provider에요청및OAuth Provider에서 전달된사용자 정보를 기반으로UserDetails 구현체를 생성하는 역할을 수행
▶서비스 계층에서구현클래스:DefaultOAuth2UserService를상속하여loadUser()를 통해 해당 작업을 수행
DefaultOAuth2UserService
。OAuth2UserService기반의구현 클래스
▶ 실제로OAuth Provider에서 전달된사용자 정보를 기반으로UserDetails 구현체를 생성하는 역할을 수행
loadUser(OAuth2UserRequest userRequest)
。OAuth Provider에서 제공된사용자정보를 조회하고OAuth2User를 생성 및 반환하는구현메서드
▶UserDetailsService.loadUserByUsername("username")역할을 수행
loadUser()를 활용한권한부여승인코드요청 / 응답과정
。loadUser()가 호출되기 이전권한부여승인코드 상 1 ~ 6번 과정이 수행되어있음.
▶OAuth2UserRequest에 포함된Access Token을 활용하여7번 과정을 시작@Service @RequiredArgsConstructor @Transactional(readOnly = true) public class MemberService extends DefaultOAuth2UserService { private final MemberRepository memberRepository; @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { // ~ 권한부여승인코드 상 1 ~ 6번이 자동으로 수행 // // 권한부여승인코드 7 ~ 8번 // OAuth2UserRequest의 Access Token, ClientRegistration을 기반으로 // OAuth Provider에게 요청 및 반환받은 사용자정보를 기반으로 UserDetails 구현체 생성 OAuth2User oAuth2User = super.loadUser(userRequest); // // 반환받은 사용자정보를 활용하여 회원가입을 수행하는 로직 정의 // return oAuth2User; } }。
super.loadUser(userRequest);이 수행된 이후응답받은사용자정보를 포함하는OAuthUser 구현체를 기반으로회원가입등의로직을 수행
▶응답받은사용자정보는 해당메서드에서 반환된OAuthUser 구현체내Map<K,V>의 attributes 필드에 포함
。회원의개인정보를 더 요구하기 위해서는OAuth Provider에게 추가적으로자원에 대한권한을 추가적으로요청
OAuth2User oAuth2User = super.loadUser(userRequest);
。loadUser() 메서드내에서OAuth2UserRequest를부모클래스 : DefaultOAuth2UserService에 전달함으로써OAuth2UserRequest내 포함된AccessToken과OAuth Provider정보를 기반으로OAuth Provider에요청및 수신받은사용자정보를 포함한OAuth2User 구현체를 반환
▶권한부여승인코드 7 ~ 8번 과정에 해당
OAuth2UserRequest
。OAuth Provider에사용자정보를요청하기 위한요청 객체
▶ 내부에Access Token,ClientRegistration등의OAuth 로그인시 필요한 정보를 포함
OAuth2AccessToken
。권한부여승인코드를 송신하여 획득한Access Token
▶OAuth2UserRequest객체.getAccessToken()를 통해 획득 가능
ClientRegistration
。application.yml내 정의한OAuth Client / Provider를 포함하는객체
▶client-id, client-secret, provider 정보, redirect-uri, scope등
。OAuth2UserRequest객체.getClientRegistration()를 통해 획득 가능
ClientRegistration객체.getRegistrationId()
。Provider 정보를반환
ex )kakao,