Kim-Baek 개발자 이야기

Spring Security - OAuth2 본문

개발/Spring

Spring Security - OAuth2

김백개발자 2020. 9. 24. 01:18

OAuth2 승인 방식의 종류

  • Authorization Code Grant Type : 권한 부여 코드 승인 타입 클라이언트가 다른 사용자 대신 특정 리소스에 접근을 요청할 때 사용됩니다. 리스소 접근을 위한 사용자 명과 비밀번호, 권한 서버에 요청해서 받은 권한 코드를 함께 활용하여 리소스에 대한 엑세스 토큰을 받는 방식입니다.
  • Implicit Grant Type : 암시적 승인 권한 부여 코드 승인 타입과 다르게 권한 코드 교환 단계 없이 엑세스 토큰을 즉시 반환받아 이를 인증에 이용하는 방식입니다.
  • Resource Owner Password Credentials Grant Type : 리소스 소유자 암호 자격 증명 타입 클라이언트가 암호를 사용하여 엑세스 토큰에 대한 사용자의 자격 증명을 교환하는 방식입니다.
  • Client Credentials Grant Type : 클라이언트 자격 증명 타입 클라이언트가 컨텍스트 외부에서 액세스 토큰을 얻어 특정 리소스에 접근을 요청할 때 사용하는 방식입니다.

Authorization Code Grant Type 방식

  • (1) 클라이언트가 파리미터러 클라이언트 ID, 리다이렉트 URI, 응답 타입을 code로 지정하여 권한 서버에 전달합니다. 정상적으로 인증이 되면 권한 코드 부여 코드를 클라이언트에게 보냅니다.
    • 응답 타입은 code, token 이 사용 가능합니다.
    • 응답 타입이 token 일 경우 암시적 승인 타입에 해당합니다.
  • (2) 성공적으로 권한 부여 코드를 받은 클라이언트는 권한 부여 코드를 사용하여 엑세스 토큰을 권한 서버에 추가로 요청합니다. 이때 필요한 파라미터는 클라이언트 ID, 클라이언트 비밀번호, 리다이렉트 URI, 인증 타입 입니다.
  • (3) 마지막으로 받은 엑세스 토큰을 사용하여 리소스 서버에 사용자의 데이터를 보냅니다.

Code

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
                .inMemory() // (1)
                .withClient("client") //(2)
                .secret("{bcrypt} $2a$10$iP9ejueOGXO29.Yio7rqeuW9.yOC4YaV8fJp3eIWbP45eZSHFEwMG")  //(3) password
                .redirectUris("http://localhost:9000/callback") // (4)
                .authorizedGrantTypes("authorization_code") // (5)
                .scopes("read_profile"); // (6)
    }
}
  • (1): 간단한 설정을 위해 메모리에 저장시키겠습니다.
  • (2): 클라이언트 이름을 작성합니다.
  • (3): 시크릿을 작성해야합니다. 스프링 시큐리티 5.0 부터는 암호화 방식이 조 변경되서 반드시 암호화해서 저장하는 것을 권장합니다. 해당 암호는 password입니다. (현재 프로젝트는 스프링부트 2.1 이기 때문에 스프링 시큐리티 5.1 의존성을 주입받습니다.)
  • (4): 리다이렉트 URI을 설정합니다.
  • (5): Authorization Code Grant 타입을 설정합니다.
  • (6): scope를 지정합니다.
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated().and()
                .requestMatchers().antMatchers("/api/**");
    }
}

@EnableWebSecurity
@AllArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //@formatter:off
		http
                .csrf().disable()
                .authorizeRequests().anyRequest().authenticated().and()
                .formLogin().and()
                .httpBasic();
        //@formatter:on
    }
}
  • 리소스 서버 설정은 configure 설정만 간단하게 설정합니다.
  • 시큐리티 설정은 기본설정에서 csrf 설정만 disable 설정했습니다.

인증

http://localhost:8080/oauth/authorize?client_id=client&redirect_uri=http://localhost:9000/callback&response_type=code&scope=read_profile 해당 페이지로 이동하면 아래와 같이 로그인 페이지(스프링 시큐리티 기본폼 이전보다 많이 이뻐졌다...)로 리다이렉트 됩니다.

 로그인 정보를 입력합니다. 소셜 가입에서 해당 소셜의 아이디로 로그인하는 것과 동일한 행위입니다.

username: user password: pass

application.yml 에서 설정한 security user 정보를 입력해줍니다.

 유저 정보 인증이 완료되면 scope에 대한 권한 승인이 페이지가 나옵니다. 소셜 가입에서 프로필 정보, 프로필 사진 등을 요구하는 것과 마찬가지입니다.

 권한 승인이 완료하면 권한 코드가 전송됩니다. Authorization Code Grant Type 방식 에서 말한 권한 부여 코드를 응답받은 것입니다.

리다이렉트된 페이지에서 위에서 발급 받은 권한 부여 코드로 권한 서버에 Access Token을 요청 받을 수 있습니다. 이 부분이 실제로 구현하지 않았고 넘겨 받은 권한 부여 코드를 기반으로 권한 서버에 수동으로 호출 해보겠습니다.

아래의 curl을 실행 해보면 응답값을 확인해 볼 수 있습니다.

curl -X POST \
  http://localhost:8080/oauth/token \
  -H 'Authorization: Basic Y2xpZW50OnBhc3N3b3Jk' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'code=xoS4mt&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A9000%2Fcallback&scope=read_profile'

만약 IntelliJ를 사용하신다면 api.http를 이용해서 더 쉽게 호출 해볼 수 있습니다. 

{ "access_token": "623d5bc4-7172-44ae-85c1-73a297e6ab04", "token_type": "bearer", "expires_in": 43199, "scope": "read_profile" }

API 호출

curl -X GET \ http://localhost:8080/api/session \ -H 'Authorization: Bearer 623d5bc4-7172-44ae-85c1-73a297e6ab04'

curl을 이용해서 요청을 보내면 아래와 같이 응답값을 확인할 수 있습니다.

{ "authorities": [], "details": { "remoteAddress": "0:0:0:0:0:0:0:1", "sessionId": null, "tokenValue": "623d5bc4-7172-44ae-85c1-73a297e6ab04" } .... }

물론 token 정보를 넘기지않거나 유효하지 않으면 401 응답을 받습니다.

 

- 참고 자료 : https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type

반응형
Comments