0. 시작하게 된 계기 및 다짐 😮

  • 이번 코드스테이츠의 백엔드 엔지니어링 개발자 부트캠프에 참여하게 되면서 현직개발자 분들의 빠른 성장을 위한 조언 중 자신만의 블로그를 이용하여 배운 것 들을 정리하는게 많은 도움이 된다 하여 시작하게 되었다.

    • 그 날 배웠던 것을 길지 않아도 좋으니 정리하며 복습하는 습관 기르기
    • 주말에 다음주에 배울 내용들을 예습
    • 코딩 문제와 java코드들은 꾸준히 학습
    • 자료구조를 이용한 알고리즘 문제 해결 학습

1. 학습 목표 😮

목표결과
OAuth2인증 방식 이해 및 학습O
Authorization Code와 Access Token의 차이점 이해O
Authorization 서버와 Resource서버 차이 이해O
Spring Security에서 OAuth2 적용 및 구현O

2. 정리 😮




< OAuth2 개요>

OAuth2 개요

1. OAuth2 OverView

  1. 용어

    • Resource Owner : 엑세스 중인 리소스의 유저

    • Client : Resource owner를 대신하여 보호된 리소스에 엑세스하는 응용프로그램

    • Resource Server : client의 요청을 수락하고 응답할 수 있는 서버

    • Authorization server : Resource server가 엑세스 토큰을 발급하는 서버(권한을 인증만 해주는 서버)

    • Authorization grant : 클라이언트가 엑세스 토큰을 얻을 때 사용하는 자격 증명
      1). Authorization Code Grant Type ,
      2). Client Credentials Grant Type
      3). Implicit Grant Type,
      4)Resource Owner Credentials Grant Type

    • Authorization code : access token을 발급받기 전에 필요한 code
      [Client ID + Client Secret로 Authorization Grant의 한 타입]

    • Access token : 보호된 리소스에 엑세스하는데 사용되는 crendentials

    • Scope : 주어진 엑세스 토큰을 사용하여 엑세스 할 수 있는 리소스 범위



1. Grant type

  • Client가 엑세스 토큰을 얻는 방법 중 하나

  • Authorizaion Code Grant/Refresh Token Grant Type등이 있음

  • 보안성 강화를 위한 목적

    (1) Authorization Code Grant

    • 엑세스 토큰을 받아오기 위해서 먼저 Authorization code를 받아 엑세스 토큰과 교환하는 방법
    • Client에서는 authorization Code만 받아오고, Server에서 Access Token을 요청진행

    (2) Refresh Token Grant Type

    • 일정기간 유효 시간이 지나서 만료된 엑세스 토큰을 편리하게 다시 받아오기 위해 사용하는 방법
    • 추후, 문서별 확인필요



2. OAuth2란?

  • 보안된 리소스에 엑세스하기 위해 클라이언트에게 권한을 제공(Authorization)하는 프로세스를
    단순화하는 프로토콜 중 한 방법
  • '클라이언트 - 서버 - 제3의 서비스' 사이의 인증
  • 편리성 + 보안상(사용자 정보 노출 방지)의 이점
  • 인증을 중개해 주는 메커니즘
  • 사용자 정보가 있는 웹 서비스에서 사용자의 인증을 대신해주고, 접근 권한에 대한 토큰을 발급 후, 서버에서 인증



3. 권한 부여 방식에 따른 프로토콜(인증 방식 OAuth2)

  1. Authorization Code Grant : 권한 부여 승인 코드 방식

    • 권한 부여 승인(엑세스 토큰 받기)위해 자체 생성한 Authorization Code를 전달하는 방식

    • 응답타입(response_type)을 code로 지정

[동작 과정]

1. Resource Owner(유저)는 Client(애플리케이션)에 소셜 로그인 버튼을 누르는 등의 서비스 요청을 보냅니다.
2. Client는 Authorization Server에 Authorization Code를 요청합니다. 이 때 미리 생성한 Client ID, Redirect URI, 응답 타입을 함께 전송합니다.
3. 로그인 팝업을 통해 Resource Owner는 로그인을 진행합니다.
4. 로그인이 확인되면 Authorization Server는 Authorization Code를 Client에 전달합니다. (이전에 요청과 함께 전달한 . Redirect URI로 Code를 전달합니다.)
5. Client는 전달받은 Authorization Code를 이용해 액세스 토큰 발급을 요청합니다. 액세스 토큰을 발급할 땐 미리 생성한 Client Secret, Redirect URI, 권한 부여 방식, 액세스 토큰을 함께 전송합니다.
6. 요청 정보를 확인한 후 Redirect URI로 액세스 토큰을 발급합니다.
7. Client는 발급받은 액세스 토큰을 이용해 Resource Server에 자원을 요청합니다.
8. 액세스 토큰을 확인한 후 요청 받은 자원을 전달합니다.
  1. Client Credentials Grant : 클라이언트 자격 증명 승인 방식

    • 클라이언트 자신이 관리하는 리소스 혹은 권한 서버에 해당 클라이언트를 위한 제한된 리소스 접근 권한이 설정되어 있는 경우 사용이 가능합니다. 이 방식은 자격 증명을 안전하게 보관할 수 있는 클라이언트에서만 사용되어야 하며, 리프레시 토큰의 사용은 불가능합니다.
    • 클라이언트가 관리하는 리소스or서버에 해당하는 리소스에 접근할 시
  2. Implicit Grant : 암묵적 승인 방식

    • 1)과 같지만, Authorization Code를 획득하여 이로 토큰을 얻는 부분이 사라짐
    • 이는 자격증명을 안전하게 저장하기 힘든 클라이언트(자바스크립트 등 스크립트 언어를 사용하는 브라우저)에게 최적화된 방식입니다
  3. Resource Owner Password Credential Grant : 자원 소유자 자격 증명 승인 방식

    • 간단하게, 로그인시 피룡한 정보(username, password)로 엑세스 토큰을 발급받는 방식
    • 자신의 서비스에서 제공하는 애플리케이션의 경우에만 사용되는 인증방식, 리프레시 토큰도 사용가능
      [Ex. 네이버 계정으로 네이버 웹툰/지도 등에 요청을 하는 경우]
    • 권한 서버, 리소스 서버, 클라이언트가 모두 같ㅇ느 시스템에 속해 있을 때만 사용이 가능



< Spring Security에서의 OAuth2 인증 >

Spring Security에서의 OAuth2 인증

0. 구글 클라우드 플랫폼 설정

  1. 승인된 리디렉션 URI
    • 서비스에서 파라미터로 인증 정보를 주었을 때, 인증 성공시 구글에서 리다이렉트할 URI
    • Spring 에서는 기본적으로 {domain}/login/oauth2/code/{소셜 서비스코드}로 URI를 지원한다.
    • 사용자가 별도로 리다이렉트 URI를 지원하는 Controller를 생성할 필요는 없음
    • a herf="oauth2/authorization/google"
      • Spring Security에서 기본적으로 제공하는 로그인 URI
  1. @애너테이션

    1). @AuthenticationPrincipa

    • authentication.getPrincipal() 을 파라미터의 타입으로 변환해서 가져오는 역할

    2). @Builder

    • 해당 Entitiy 등을 Builder를 통해 생성

[예제]

Bag bag = Bag.builder()
		.name("name")
        	.money(1000)
        	.memo("memo")
            	.letter("This is the letter")
            	.box("This is the box")
        	.build();



  1. Code 분석

    1) .defaultSuccessUrl("/")

    • 로그인을 성공 후, 이동할 페이지를 직접 지정



  1. Spring Security OAuth

    0). UserDetailsService 와 DefaultOAuth2UserService 차이점

    • UserDetailsService : 해당 클래스의 loadUserByUsername메소드는
      loginProcessingUrl(form의 action을 통해 값이 반환될 url 지정)이 동작할 때 불리는 클래스
      제3 로그인(ex. 구글) 로그인 이후 호출된다.

    • DefaultOAuth2UserService : 해당 클래스의 Form형태가 아닌 OAuth2형태로 로그인을 통해 불리고 loadUser는 Oauth2로그인 이후
      불리는 메소드

    1). 구글 회원 프로필 정보 받기

    • (1) 코드 받기(인증)
    • (2) 엑세스 토큰(권한)
    • (3) 사용자 프로필 정보를 가져오기
    • (4) 3번에서 가져온 정보를 토대로, 회원가입 완료
      • 부족할 경우, 추가적인 구성 정보를 기입

    2). 과정

    • 구글 로그인 버튼 클릭 → 구글 로그인 창 → 로그인 완료 → code 리턴(OAuth-Client 라이브러리) → AccessToken 요청 -> userRequest 정보 → loadUser 함수 호출 → 구글로부터 회원프로필 정보를 받아온다

[PrincipalOauth2UserService.java 클래스 Code]

 import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

@Service
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException{
        return super.loadUser(userRequest);
    }
}

 - loadUser 메서드를 Override하는데 이 메서드는 구글로부터 받은 userRequest 데이터에 대한 후처리 함수입니다.
 - userRequest에 담긴 정보를 확인할 수 있는 메서드
  1). userRequest.getClientRegistration()
  2). userRequest.getAccessToken().getTokenValue()
  3). super.loadUser(userRequest).getAttributest()

[SecurityConfig 클래스 수정]

public class SecurityConfig {

    @Autowired
    private PrincipalOauth2UserService principalOauth2UserService; // 추가

		...
		
		@Bean
		public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
			http.
				...
				.loginPage("/login")
        .userInfoEndpoint() // 추가  (1)
        .userService(principalOauth2UserService); // 추가 
		}
}

(1) .userInfoEndpoint()
    - oauth2Login 성공 이후의 설정을 시작한다.



3). Authentication 정보 확인

[IndexController 클래스 수정 ]

public class IndexController{

   .......
   
   @GetMapping("/loginTest")
    public @ResponseBody String loginTest(Authentication authentication) {
        System.out.println("============/loginTest===========");
        PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal(); //(2)
        System.out.println("authentication : " + principalDetails.getMember());
        return "세션 정보 확인";
    }

    @GetMapping("/loginTest2")
    public @ResponseBody String loginTest2(@AuthenticationPrincipal PrincipalDetails principalDetails){ //(3)
        System.out.println("============/loginTest2/================");
        System.out.println("userDetails : " + principalDetails.getMember());
        return "세션 정보 확인2";
    }

    @GetMapping("/loginTest3")
    public @ResponseBody String loginOAuthTest(Authentication authentication, @AuthenticationPrincipal OAuth2User oauth){
        System.out.println("===============/loginOAuthTest/================");
        OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal();   //(3)
        System.out.println("authentication : " + oAuth2User.getAttributes());
        System.out.println("oAuth2User : " + oauth.getAttributes());
        return "세션 정보 확인3";
    }

}


(1) .getPrincipal();
    - authentication에서 userDetails를 구현한 사용자 객체를 Return 한다.
    - 여기서는 PrincipalDetails로 다운 캐스팅하여 원하는 형태로 가져옴

(2). @AuthenticationPrincipa 
    - authentication.getPrincipal() 을 파라미터의 타입으로 변환해서 가져오는 역할

(3). OAuth2User
    - Oauth로 로그인시, 해당 OAuth2 로그인 정보를 Authentication에서 가져와 casting 



4). 스프링 시큐리티(세션)

  • 일반 로그인 -> PrincipalDetails( implements UserDeatils) -> loadUserByUsername메소드 -> (보통 Form을 통한 로그인, OAuth로그인이 아닌)

  • OAuth 로그인 -> PrincipalOauth2UserService(extends DefaultOAuth2UserService) -> loadUser 메소드 -> OAuth을 통한 로그인시, 로그인 이후 처리를 위한 메소드 호출

  • 이 둘을 묶어서 한번에 처리

[PrintcipalDetials 클래스]

@Data
public class PrincipalDetails implements UserDetails, OAuth2User {	

		...
		@Override
	  public Map<String, Object> getAttributes() {
	      return null;
	  }
	
	  @Override
	  public String getName() {
	      return null;
	  }
}



  1. PrintcipalDetails

    0). ResponseEntity와 @ResponseBody 차이점

    • @ResponseBody는 파라미터를 받아서 response로 응답하고
    • ResponseEntity는 객체를 response로 응답

    1). 스프링 시큐리티 세션

    • 세션 정보는 언제나 Authentication 객체 하나만 가지고 올 수 있음



3. 피드백 😮

  • OAtuh2란, 클라이언트-서버-제3서비스 형태로, 사용자가 이용하는 클라이언트 서버에서 다른 서버의 사용자 정보로 로그인을 해줄수 있게 권한을 제공하는 프로토콜 중 한 방법이다.



  • OAuth2의 과정은 클라이언트쪽에서 다른 서버의 자원을 요청했을시, Authorzation 서버에서 유저에게 접속을 허할껀지 확인을 후 허한다면, Client쪽에 Authorzation Code를 넘겨준다. 이후, 이 Code를 이용해 Access Token을 받아 이를 기반으로 Resource에 접근하여 정보를 얻음


4. 앞으로 해야 될 것 😮

  • 매일 꾸준히 할 것
    • 꾸준히 velog 작성
    • Java 언어 및 Algorithm 공부(Coding-Test)
    • 틈틈히 운동 하기

  • 내일 해야 할 것
    • Cloud 운영 환경 구성
profile
Will be great Backend-developer

0개의 댓글