Spring/security

[시큐리티] OAuth2 - 승인 코드 그랜트 유형 깃허브로 연습

라임온조 2023. 3. 31. 11:24

전제 조건

  • 권한 부여 서버와 리소스 서버로 깃허브를 사용한다
  • 클라이언트는 내가 작성한 스프링 백엔드 코드다
  • 사용자는 깃허브를 사용하면서 내가 작성한 스프링 백엔드 코드에 접근한 사람이다

 

1. 권한 부여 서버에게 클라이언트를 알리기

  • 깃허브에서 클라이언트의 이름, 홈페이지, 깃허브가 클라이언트를 다시 호출할 링크를 지정하기
  • 양식 입력 후 클라이언트 ID와 클라이언트 비밀을 얻을 수 있다

 

2. 클라이언트에 인증 방식으로 OAuth2를 사용할 것이라고 선언하기

  • build.gradle 혹은 pom.xml에 OAuth2 의존성을 주입해야 한다
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
}
  • config 파일에 OAuth2를 사용할 것이라고 선언한다
@Override
protected void configure(HttpSecurity http) throws Exception{
    http.oauth2Login(); // OAuth2LoginAuthenticationFilter를 필터 체인에 추가한다. 이 필터는 요청을 가로채고 OAuth2 인증 논리를 적용한다
    http.authorizeRequests()
            .anyRequest()
            .authenticated();
}

 

3. 클라이언트와 관련된 세부 사항을 등록하기

ClientRegistration

  • 클라이언트가 사용할 권한 부여 서버를 등록하기 위해 사용하는 인터페이스
  • 스프링 시큐리티가 제공
  • 권한 부여 서버를 등록한다는 말이 있어서 권한 부여 서버를 나타내는 것인가? 착각할 수 있지만 이름에도 나와있듯이 클라이언트를 나타내는 것이다. 즉, 클라이언트를 등록할 수 있게 해 주는 인터페이스인데 그 등록 내용에 클라이언트가 사용할 권한 부여 서버를 등록하는 내용도 있으니 권한 부여 서버를 등록하기 위해 사용할 수 있는 것이다.
  • 클라이언트의 다양한 세부 정보를 포함하고 있다

방법 1 ClientRegistration 생성 후 내용 등록

  • 권한 부여 서버의 설명서를 찾아서 필요한 내용들을 등록해야 한다
private ClientRegistration clientRegistration() {
    ClientRegistration cr = ClientRegistration.withRegistrationId("github")
            .clientId("a7553955a0c534ec5e6b")
            .clientSecret("1795b30b425ebb79e424afa51913f1c724da0dbb")
            .scope(new String[]{"read:user"})
            .authorizationUri("https://github.com/login/oauth/authorize")
            .tokenUri("https://github.com/login/oauth/access_token")
            .userInfoUri("https://api.github.com/user")
            .userNameAttributeName("id")
            .clientName("GitHub")
            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
            .redirectUriTemplate("{baseUrl}/{action}/oauth2/code/{registrationId}")
            .build();
    return cr;
}

방법 2 CommonOAuth2Provider 사용

  • 구글, 깃허브, 페이스북, 옥타 등의 사이트를 권한 부여 서버로 사용할 때 사용 가능
  • 방법1보다 간단하게 등록 가능
private ClientRegistration clientRegistration() {
    return CommonOAuth2Provider.GITHUB.getBuilder("github")
            .clientId("")
            .clientSecret("")
            .build();
}

 

4. 3에서 등록한 클라이언트를 사용하는 방법 설정

ClientRegistrationRepository

  • ClientRegistration을 인증에 이용하도록 설정하기 위해 사용
  • OAuth2LoginAuthenticationFilter는 ClientRegistrationRepository에서 ClientRegistration 세부 정보를 얻을 수 있다.
  • ClientRegistration 의 등록 ID로 ClientRegistration을 찾는다

방법 1 InMemoryClientRegistrationRepository 사용

  • ClientRegistration의 인스턴스를 메모리에 저장
@Bean
public ClientRegistrationRepository clientRepository() {
    var c = clientRegistration();
    return new InMemoryClientRegistrationRepository(c);
}

방법 2 HttpSecurity 객체의 oauth2Login()의 매개 변수로 Customizer 객체 이용

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.oauth2Login(c -> {
        c.clientRegistrationRepository(clientRepository());
    });

    http.authorizeRequests()
            .anyRequest().authenticated();
}

 

5. 인증된 사용자의 세부 정보 얻기

  • 스프링 시큐리티에서 인증된 사용자의 세부 정보는 Authentication 객체 형태로 SecurityContext에 저장된다.
  • Authentication 객체의 구현은 OAuth2AuthenticationToken이기 때문에 컨트롤러 메서드 매개변수로 이를 넣어주면 여기서 인증된 사용자의 세부 정보를 얻을 수 있다.
@GetMapping("/")
public String main(OAuth2AuthenticationToken token){
    logger.info(String.valueOf(token.getPrincipal()));
    return "main.html";
}

 

6. 결과

  • 사용자가 클라이언트의 http://localhost:8080으로 접속하면 깃허브 인증 페이지로 리디렉션 된다. 
  • 사용자가 깃허브에서 올바르게 로그인을 하면 클라이언트는 깃허브로부터 액세스 토큰을 얻을 수 있는 코드를 얻게 되고, 이 코드를 이용해 깃허브로부터 액세스 토큰을 얻는다.
  • 클라이언트는 로그인 된 사용자의 세부 정보를 얻을 수 있다.

 

+ ClientRegistration과 ClientRegistrationRepository를 작성하지 않는 방법

1) 일반적인 공급자일 경우(구글, 깃허브 등)

application.properties 파일에 client-id와 client-secret를 등록하면 스프링 부트가 속성 파일을 바탕으로 자동으로 ClientRegistration과 ClientRegistrationRepository를 생성해주기 때문에 따로 코드를 작성하지 않아도 된다.

spring.security.oauth2.client.registration.github.client-id=a7553955a0c534ec5e6b
spring.security.oauth2.client.registration.github.client-secret=1795b30b425ebb79e424afa51913f1c724da0dbb

2) 일반적인 공급자가 아닐 경우

spring.security.oauth2.client.provider로 시작하는 속성 그룹으로 권한 부여 서버에 관한 세부 정보를 application.properties파일에 적어야 한다.

spring.security.oauth2.client.provider.myprovider.authorization-uri=

 

전체 코드 

 

GitHub - wikibook/spring-security: 《스프링 시큐리티 인 액션》 예제 코드

《스프링 시큐리티 인 액션》 예제 코드. Contribute to wikibook/spring-security development by creating an account on GitHub.

github.com

 

'Spring > security' 카테고리의 다른 글

[시큐리티] OAuth 2  (0) 2023.03.30
[시큐리티] 토큰  (0) 2023.03.29
[시큐리티] CORS  (0) 2023.03.28
[시큐리티] CSRF  (0) 2023.03.27
[시큐리티] 필터  (0) 2023.03.23