0. 시작하게 된 계기 및 다짐 😮
이번 코드스테이츠의 백엔드 엔지니어링 개발자 부트캠프
에 참여하게 되면서 현직개발자 분들의 빠른 성장을 위한 조언 중 자신만의 블로그를 이용하여 배운 것 들을 정리하는게 많은 도움이 된다 하여 시작하게 되었다.
1. 학습 목표 😮
목표 | 결과 |
---|---|
OAuth2인증 방식 이해 및 학습 | O |
Authorization Code와 Access Token의 차이점 이해 | O |
Authorization 서버와 Resource서버 차이 이해 | O |
Spring Security에서 OAuth2 적용 및 구현 | O |
2. 정리 😮
OAuth2 개요
1. OAuth2 OverView
용어
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
(2) Refresh Token Grant Type
2. OAuth2란?
3. 권한 부여 방식에 따른 프로토콜(인증 방식 OAuth2)
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. 액세스 토큰을 확인한 후 요청 받은 자원을 전달합니다.
Client Credentials Grant : 클라이언트 자격 증명 승인 방식
Implicit Grant : 암묵적 승인 방식
Resource Owner Password Credential Grant : 자원 소유자 자격 증명 승인 방식
Spring Security에서의 OAuth2 인증
0. 구글 클라우드 플랫폼 설정
@애너테이션
1). @AuthenticationPrincipa
2). @Builder
[예제]
Bag bag = Bag.builder() .name("name") .money(1000) .memo("memo") .letter("This is the letter") .box("This is the box") .build();
Code 분석
1) .defaultSuccessUrl("/")
Spring Security OAuth
0). UserDetailsService 와 DefaultOAuth2UserService 차이점
UserDetailsService : 해당 클래스의 loadUserByUsername메소드는
loginProcessingUrl(form의 action을 통해 값이 반환될 url 지정)이 동작할 때 불리는 클래스
제3 로그인(ex. 구글) 로그인 이후 호출된다.
DefaultOAuth2UserService : 해당 클래스의 Form형태가 아닌 OAuth2형태로 로그인을 통해 불리고 loadUser는 Oauth2로그인 이후
불리는 메소드
1). 구글 회원 프로필 정보 받기
2). 과정
[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;
}
}
PrintcipalDetails
0). ResponseEntity와 @ResponseBody 차이점
1). 스프링 시큐리티 세션
3. 피드백 😮
OAtuh2란, 클라이언트-서버-제3서비스 형태로, 사용자가 이용하는 클라이언트 서버에서 다른 서버의 사용자 정보로 로그인을 해줄수 있게 권한을 제공하는 프로토콜 중 한 방법이다.
OAuth2의 과정은 클라이언트쪽에서 다른 서버의 자원을 요청했을시, Authorzation 서버에서 유저에게 접속을 허할껀지 확인을 후 허한다면, Client쪽에 Authorzation Code를 넘겨준다. 이후, 이 Code를 이용해 Access Token을 받아 이를 기반으로 Resource에 접근하여 정보를 얻음
4. 앞으로 해야 될 것 😮