OAuth 2.0 개요

RFC 6749 - OAuth 2.0 인증 프레임워크는 타사 애플리케이션을 사용하여 서비스를 인증하기 위한 프로토콜을 지정합니다. OAuth 2.0은 토큰을 사용하여 서비스 및 사용자로부터 인증을 추상화합니다. 이 방법은 서비스 소유자가 사용자 자격 증명을 처리할 필요가 없으므로 더 안전합니다. RFC 5849 OAuth 1.0을 대체합니다.

OAuth 2.0 프레임워크는 공개 또는 기밀이라는 두 가지 클라이언트 유형과 인증 코드 흐름, 암시적 코드 부여 및 기타 여러 가지 인증을 위한 흐름을 정의합니다. 일반적인 Qt 애플리케이션은 공용 네이티브 애플리케이션으로 간주됩니다. 공개 클라이언트 애플리케이션은 비밀번호와 같은 민감한 정보를 포함하고 있다고 신뢰할 수 없는 애플리케이션으로, 제공된 바이너리 내에 포함될 수 있습니다.

네이티브 앱용 RFC 8252 OAuth 2.0은 네이티브 애플리케이션에 대한 모범 사례를 추가로 정의합니다. 특히 RFC 8252는 브라우저를 통한 인증 흐름을 권장합니다. 따라서 QtNetworkAuth 클래스는 이 흐름의 구체적인 구현을 제공합니다.

Qt 6.9의 새로운 기능인 QtNetworkAuthRFC 8628 - OAuth 2.0 디바이스 권한 부여를 지원합니다. 이 장치 흐름은 입력 기능이 제한적이거나 실용적이지 않은 장치를 위한 것입니다. 이 플로우에서 권한 부여는 디바이스 대신 스마트폰과 같은 보조 디바이스를 사용합니다. 이러한 디바이스의 예로는 텔레비전, 미디어 콘솔, 기계 HMI 및 IoT 디바이스가 있습니다. 그런 다음 사용자는 스마트폰의 애플리케이션을 사용하여 디바이스를 인증할 수 있습니다.

다음 표는 Qt Network Authorization 에서 지원하는 두 가지 OAuth 2.0 플로우를 강조합니다:

측면인증 코드 흐름디바이스 인증 흐름
네트워크 연결
사용자 상호 작용동일한 디바이스의 브라우저/사용자 에이전트다른 디바이스의 브라우저/사용자 에이전트
리디렉션 처리 필요아니요
디바이스의 입력 기능다양한 입력 기능입력 기능이 제한적이거나 없음
대상데스크톱 및 모바일 앱TV, 콘솔, HMI, IoT 디바이스

OAuth 2.0을 사용하려면 일반적으로 브라우저인 사용자 에이전트를 사용해야 합니다. 자세한 내용은 Qt OAuth2 브라우저 지원을 참조하세요.

OAuth 2.0 클래스

Qt Network Authorization 는 구체적 및 추상적 OAuth 2.0 클래스를 모두 제공합니다. 추상 클래스는 사용자 정의 플로우를 구현하기 위한 것이고, 구체 클래스는 구체적인 구현을 제공합니다.

C++ 클래스 목록은 QtNetworkAuth 페이지를 참조하세요.

Qt Network Authorization 에는 OAuth 2.0 플로우를 구현하기 위한 두 개의 추상 클래스가 있습니다:

권한 부여 코드 흐름

이 섹션에서는 네이티브 애플리케이션을 위한 RFC 6749 - 인증 코드RFC 8252 - 네이티브 앱의 인증 요청의 인증 코드 흐름에 대한 개요를 설명합니다.

다음 샘플 설정을 고려하세요:

QOAuth2AuthorizationCodeFlow m_oauth;
QOAuthUriSchemeReplyHandler m_handler;

m_oauth.setAuthorizationUrl(QUrl(authorizationUrl));
m_oauth.setTokenUrl(QUrl(accessTokenUrl));
m_oauth.setClientIdentifier(clientIdentifier);
m_oauth.setRequestedScopeTokens({scope});

connect(&m_oauth, &QAbstractOAuth::authorizeWithBrowser, this, &QDesktopServices::openUrl);
connect(&m_oauth, &QAbstractOAuth::granted, this, [this]() {
    // Here we use QNetworkRequestFactory to store the access token
    m_api.setBearerToken(m_oauth.token().toLatin1());
    m_handler.close();
});

m_handler.setRedirectUrl(QUrl{"com.example.myqtapp://oauth2redirect"_L1});
m_oauth.setReplyHandler(&m_handler);

// Initiate the authorization
if (m_handler.listen()) {
    m_oauth.grant();
}

권한 부여 흐름 단계

RFC 6749 권한 부여 코드 흐름에는 리소스 권한 부여(필요한 사용자 인증 포함)와 액세스 토큰 요청이라는 두 가지 주요 단계가 있습니다. 그 다음에는 선택적으로 액세스 토큰 사용 및 액세스 토큰 새로 고침이 이어집니다. 다음 그림은 이러한 단계를 보여줍니다:

인증 서버와 브라우저를 사용하여 Qt 애플리케이션의 간소화된 인증 프로세스

  • 권한 부여 단계에서는 사용자가 인증되고 사용자가 리소스에 대한 액세스를 승인합니다. 이를 위해서는 사용자의 브라우저 상호 작용이 필요합니다.
  • 권한 부여 후에는 수신된 인증 코드를 사용하여 액세스 토큰을 요청하고 선택적으로 새로 고침 토큰을 요청합니다.
  • 액세스 토큰이 획득되면 애플리케이션은 이를 사용하여 관심 있는 리소스에 액세스합니다. 액세스 토큰은 리소스 요청에 포함되며, 토큰의 유효성을 확인하는 것은 리소스 서버의 몫입니다. 무기명 토큰을 요청의 일부로 토큰을 포함하는 방법에는 여러 가지가 있습니다. HTTP Authorization 헤더에 토큰을 포함하는 것이 가장 일반적인 방법입니다.
  • 액세스 토큰 갱신. 액세스 토큰은 일반적으로 1시간 후에 만료되는 등 비교적 빠르게 만료됩니다. 애플리케이션이 액세스 토큰과 함께 새로 고침 토큰을 받은 경우 새로 고침 토큰을 사용하여 새 액세스 토큰을 요청할 수 있습니다. 애플리케이션은 수명이 긴 새로 고침 토큰을 유지하여 새로운 인증 단계(따라서 또 다른 브라우저 상호 작용)의 필요성을 피할 수 있습니다.

세부 정보 및 사용자 지정

OAuth 2.0 흐름은 동적이며 처음에는 사양을 구현하는 것이 까다로울 수 있습니다. 아래 그림은 성공적인 인증 코드 흐름의 주요 세부 사항을 보여줍니다.

특정 이벤트 호출을 보여주는 OAuth 2.0 흐름의 세부 정보

명확성을 위해 일부 신호는 생략되었지만 세부 사항과 주요 사용자 지정 포인트는 모두 설명되어 있습니다. 사용자 지정 포인트는 애플리케이션에서 사용할 수 있는 다양한 신호 및 슬롯과 QAbstractOAuth::setModifyParametersFunction() 및 QAbstractOAuth2::setNetworkRequestModifier()로 설정할 수 있는 콜백입니다.

응답 핸들러 선택하기

어떤 핸들러를 사용할지는 redirect_uri 요소에 따라 결정됩니다. redirect_uri 은 인증 단계가 완료되면 브라우저가 리디렉션되는 위치로 설정됩니다.

네이티브 애플리케이션에서 권한 부여 응답을 수신하기 위해 RFC 8252는 개인 사용, 루프백 및 https의 세 가지 주요 응답 URI 스키마를 지정합니다.

  • 비공개 사용 URI: OS에서 애플리케이션이 사용자 지정 URI 스키마를 등록하도록 허용하는 경우에 사용할 수 있습니다. 이러한 사용자 지정 스키마가 있는 URL을 열려고 하면 관련 기본 애플리케이션이 열립니다. QOAuthUriSchemeReplyHandler 을 참조하세요.
  • HTTPS URI: OS에서 애플리케이션이 사용자 지정 HTTPS URL을 등록하도록 허용하는 경우에 사용할 수 있습니다. 이 URL을 열려고 하면 관련 기본 애플리케이션이 열립니다. 이 방식은 OS에서 지원하는 경우에 권장됩니다. QOAuthUriSchemeReplyHandler 을 참조하세요.
  • 루프백 인터페이스: 일반적으로 데스크톱 애플리케이션 및 개발 중인 애플리케이션에 사용됩니다. QOAuthHttpServerReplyHandler 은 리디렉션을 처리할 로컬 서버를 설정하여 이러한 URI를 처리하도록 설계되었습니다.

선택은 다음과 같은 여러 요인에 따라 달라집니다:

  • 인증 서버 공급업체에서 지원하는 리디렉션 URI. 지원은 공급업체마다 다르며 특정 클라이언트 유형 및 운영 체제에 따라 달라지는 경우가 많습니다. 또한 애플리케이션의 게시 여부에 따라 지원 여부가 달라질 수 있습니다.
  • 대상 플랫폼에서 지원하는 리디렉션 URI 스키마.
  • 애플리케이션별 사용성, 보안 및 기타 요구 사항.

RFC 8252에서는 다른 방법보다 보안 및 사용성 측면에서 이점이 있는 https 스키마를 사용할 것을 권장합니다.

OAuth 2.0 디바이스 권한 부여

RFC 8628 OAuth 2.0 디바이스 권한 부여는 입력 기능이 제한적이거나 사용자 에이전트 브라우저 사용이 실용적이지 않은 연결된 디바이스를 위한 것입니다. 이 플로우를 사용하는 디바이스의 예로는 인증을 위해 외부 디바이스가 필요한 스마트 기기 등이 있습니다.

다음 샘플 설정을 고려하세요:

m_deviceFlow.setAuthorizationUrl(QUrl(authorizationUrl)); m_deviceFlow.setTokenUrl(QUrl(accessTokenUrl)); m_deviceFlow.setRequestedScopeTokens({scope}); m_deviceFlow.setClientIdentifier(clientIdentifier);// 클라이언트 비밀은 인증 서버에 따라 필요합니다m_deviceFlow에 따라 다릅니다.setClientIdentifierSharedKey(clientSecret); connect(&m_deviceFlow, &QOAuth2DeviceAuthorizationFlow::authorizeWithUserCode, this,[](const QUrl &verificationUrl, const QString &userCode, const QUrl &completeVerificationUrl) { if (completeVerificationUrl.isValid()) { // 인증 서버가  URL 파라미터의 일부로 필요한 데이터가 이미 포함된 //  완전한 URL을 제공한 경우 , // 이를 사용하도록 선택할 수 있습니다.            qDebug() << "Complete verification uri:" << completeVerificationUrl;
        } else { // 인증 서버는 인증 URL만 제공했습니다.            qDebug() << "Verification uri and usercode:" << verificationUrl << userCode;
        } } ); connect(&m_deviceFlow, &.QAbstractOAuth::granted, this, [this](){ // 여기서는 QNetworkRequestFactory를 사용하여 액세스 토큰을 저장합니다m_api.setBearerToken(m_deviceFlow.token().toLatin1()); }); m_deviceFlow.grant();

디바이스 권한 부여 단계

디바이스 권한 부여 흐름은 권한 초기화, 토큰 폴링, 권한 부여 완료의 세 가지 주요 단계로 구성됩니다. 그 다음에는 선택적으로 토큰 사용 및 토큰 새로 고침이 이어집니다. 다음 그림은 이러한 단계를 보여줍니다:

별도의 장치에서 브라우저를 사용하여 Qt 애플리케이션의 권한 부여 흐름 간소화

  • 권한 부여는 권한 부여 서버에 HTTP 요청을 전송하여 초기화됩니다. 인증 서버는 사용자 코드, 인증 URL, 디바이스 코드를 응답으로 제공합니다.
  • 인증이 초기화되면 사용자에게 인증 완료를 위한 사용자 코드와 인증 URL이 제공됩니다. 최종 사용자에게 제공되는 메커니즘은 화면에 표시되는 URL, QR코드, 이메일 등 다양합니다. 자세한 내용은 RFC 8628 - 사용자 상호작용을 참조하세요.
  • 최종 사용자가 인증을 완료할 때까지 기다리는 동안 디바이스 플로우는 인증 서버에서 토큰을 폴링합니다. 이전 단계에서 받은 장치 코드는 인증 세션과 일치하는 데 사용됩니다. 폴링 간격은 인증 서버에서 결정하며 일반적으로 5초입니다.
  • 최종 사용자가 인증을 수락하거나 거부하면 인증 서버는 요청된 토큰으로 폴링 요청에 응답하거나 거부된 경우 오류 코드를 반환하고 인증이 완료됩니다.

세부 정보 및 사용자 지정

다음 그림은 디바이스 권한 부여 흐름을 더 자세히 설명합니다. 이 그림은 때때로 필요한 주요 사용자 지정 포인트를 보여줍니다. 예를 들어 독점 매개변수 또는 추가 인증 자격 증명 등이 있습니다.

특정 이벤트 호출을 보여주는 OAuth 2.0 디바이스 권한 부여 흐름의 세부 정보

토큰 새로 고침

토큰을 새로 고치려면 인증 서버가 인증 중에 새로 고침 토큰을 제공해야 합니다. 새로 고침 토큰을 제공하는 것은 권한 부여 서버에 달려 있습니다. 일부 서버는 항상 제공하도록 선택할 수 있고, 일부 서버는 제공하지 않을 수도 있으며, 권한 부여 요청에 특정 scope 이 있는 경우 제공하기도 합니다.

다음 그림은 토큰 새로 고침에 대해 자세히 설명합니다:

특정 이벤트 호출을 보여주는 토큰 새로 고침 세부 정보

위 그림에서 볼 수 있듯이 토큰을 새로 고칠 때 일반적인 사용자 지정 포인트도 사용할 수 있습니다.

애플리케이션 시작 후 토큰을 새로 고치려면 애플리케이션에서 새로 고침 토큰을 안전하게 유지하고 QAbstractOAuth2::setRefreshToken 으로 설정해야 합니다. 그런 다음 QAbstractOAuth2::refreshTokens 을 호출하여 새 토큰을 요청할 수 있습니다.

Qt 6.9의 새로운 기능으로 애플리케이션이 토큰을 자동으로 새로 고칠 수 있습니다( QAbstractOAuth2::accessTokenAboutToExpire, QAbstractOAuth2::autoRefresh, QAbstractOAuth2::refreshLeadTime 참조).

새로 고침 토큰의 만료 시간은 일반적으로 인증 서버에서 (서버의 문서와는 별도로) 표시하지 않습니다. 유효 기간은 며칠, 몇 달 또는 그 이상일 수 있습니다. 또한 다른 토큰과 마찬가지로 새로 고침 토큰도 사용자가 언제든지 취소하여 무효화할 수 있습니다. 따라서 QAbstractOAuth::requestFailed 또는 QAbstractOAuth2::serverReportedErrorOccurred 을 통해 새로 고침 시도 실패를 올바르게 감지하는 것이 중요합니다.

OAuth 2.0 플로우에는 많은 사용자 상호 작용이 필요하며, 이는 사용자 경험에 방해가 될 수 있습니다. 이러한 상호 작용을 최소화하기 위해 토큰을 자동으로 새로 고칠 수 있습니다. 자세한 내용은 RFC 6749 - 액세스 토큰 새로 고침을 참조하세요.

Qt OpenID Connect 지원

OIDC(OpenID Connect) 는 OAuth 2.0을 기반으로 하는 간단한 ID 계층입니다. OIDC는 인증 서버를 사용하여 사용자의 신원을 인증할 수 있습니다. 간단한 사용자 프로필 정보에 액세스하는 것도 OIDC를 통해 가능합니다.

Qt의 OIDC 지원은 현재 ID 토큰을 얻는 것으로 제한되어 있습니다. ID 토큰은 인증 이벤트에 대한 클레임이 포함된 JSON 웹 토큰(JWT) 입니다.

참고: ID 토큰 유효성 검사 또는 ID 토큰 암호 해독은 현재 구현되어 있지 않습니다. JWT 토큰 서명 또는 확인을 위해서는 타사 JWT 라이브러리를 사용해야 합니다.

애플리케이션이 수신된 토큰의 유효성을 검사할 수 있다고 가정하면 토큰을 사용하여 사용자의 신원을 안정적으로 설정할 수 있습니다(OIDC 공급자 자체를 신뢰할 수 있는 한).

ID 토큰은 민감한 정보이므로 비밀로 유지해야 하며 액세스 토큰과 동일하지 않습니다. ID 토큰은 API 호출에서 전송하기 위한 것이 아니며, 액세스 토큰은 그러한 용도로 사용됩니다. 일부 공급업체는 액세스 토큰에 동일한 JWT 형식을 사용할 수 있지만 동일한 형식을 사용하는 실제 ID 토큰과 혼동해서는 안 됩니다. ID 토큰의 경우 토큰을 받는 클라이언트가 토큰을 확인할 책임이 있는 반면, 액세스 토큰의 경우 토큰을 수락하는 리소스 서버가 확인을 담당합니다.

ID 토큰 받기

ID 토큰을 얻는 방법은 액세스 토큰을 얻는 방법과 비슷합니다. 먼저 적절한 범위를 설정해야 합니다. 권한 부여 서버 공급업체는 profileemail 과 같은 추가 범위 지정자를 지원할 수 있지만 모든 OIDC 요청에는 openid 범위가 포함되어야 합니다:

m_oauth.setRequestedScopeTokens({"openid"});

OIDC의 경우 nonce 매개 변수를 사용할 것을 강력히 권장합니다. 이는 적절한 NonceMode 가 설정되어 있는지 확인하여 수행됩니다.

// This is for illustrative purposes, 'Automatic' is the default mode
m_oauth.setNonceMode(QAbstractOAuth2::NonceMode::Automatic);

마지막 단계로 QAbstractOAuth2::granted 신호 또는 QAbstractOAuth2::idTokenChanged 신호를 직접 수신할 수 있습니다:

connect(&m_oauth, &QAbstractOAuth2::idTokenChanged, this, [this](const QString &token) {
    Q_UNUSED(token); // Handle token
});

ID 토큰 유효성 검사하기

수신한 ID 토큰의 유효성을 검사하는 것은 인증 흐름의 중요한 부분이며, 완전히 구현된 경우 다소 복잡한 작업입니다. OpenID Connect ID 유효성 검사에서 전문을 참조하세요.

간단히 요약하면 유효성 검사는 다음 단계로 구성됩니다:

  • 필요한 경우 토큰 암호 해독(JWE 참조)
  • 토큰 헤더, 페이로드 및 서명 추출하기
  • 서명 유효성 검사
  • 페이로드의 필드 유효성 검사(예: aud, iss, exp, nonce, iat)

Qt는 현재 ID 토큰 유효성 검사를 지원하지 않지만 jwt-cpp와 같은 서드파티 JWT 라이브러리가 있습니다.

ID 토큰 검증 예제

이 섹션에서는 간단한 검증 예제를 설명합니다. 전제 조건으로 개발 환경에는 애플리케이션 프로젝트의 소스 디렉터리 아래에 있는 include 폴더에 OpenSSL 라이브러리와 jwt-cpp가 있어야 합니다.

애플리케이션 프로젝트의 CMakeLists.txt 파일에서 먼저 사전 요구 사항이 충족되는지 확인합니다:

find_package(OpenSSL 1.0.0 QUIET)
set(JWT_CPP_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include")
if(OPENSSL_FOUND AND EXISTS "${JWT_CPP_INCLUDE_DIR}/jwt-cpp/jwt.h")

그런 다음 필요한 인클루드 및 라이브러리를 추가합니다:

    target_include_directories(networkauth_oauth_snippets PRIVATE "${JWT_CPP_INCLUDE_DIR}")
    target_link_libraries(networkauth_oauth_snippets PRIVATE OpenSSL::SSL OpenSSL::Crypto)
    target_compile_definitions(networkauth_oauth_snippets PRIVATE JWT_CPP_AVAILABLE)

애플리케이션 소스 파일에 검증 라이브러리를 포함합니다:

#ifdef JWT_CPP_AVAILABLE
#include "jwt-cpp/jwt.h"
#endif

애플리케이션이 ID 토큰을 받으면 이를 검증할 차례입니다. 먼저 JSON 웹 키 집합(JWKS)에서 일치하는 키를 찾습니다( OpenID 연결 검색 참조).

try {
    const auto jwt = jwt::decode(m_oauth.idToken().toStdString());
    const auto jwks = jwt::parse_jwks(m_jwks->toJson(QJsonDocument::Compact).toStdString());
    const auto jwk = jwks.get_jwk(jwt.get_key_id());

그런 다음 실제 확인을 수행합니다:

   // 여기서는 모듈러스와 지수를 사용하여 키를 도출합니다 const auto n = jwk.get_jwk_claim("n").as_string(); // 모듈러스 const auto e = jwk.get_jwk_claim("e").as_string(); // 지수 if (n.empty() || e.empty()) {...        qWarning() << "Modulus or exponent empty";
       return false; } if (jwt.get_algorithm() != "RS256") { // 이 예제는 RS256만 지원합니다.        qWarning() << "Unsupported algorithm:" << jwt.get_algorithm();
       return false; } if (jwk.get_jwk_claim("kty").as_string() != "RSA") {        qWarning() << "Unsupported key type:" << jwk.get_jwk_claim("kty").as_string();
       return false; } if (jwk.has_jwk_claim("use") && jwk.get_jwk_claim("use").as_string() != "sig") {        qWarning() << "Key not for signature" << jwk.get_jwk_claim("use").as_string();
       return false; } // 간단한 최소한의 검증(특수한 경우 생략, 예: 'sub' 검증). // jwt-cpp는 'exp', 'iat', 'nbf'도 존재하는지 확인합니다. const auto keyPEM = jwt::helper::create_public_key_from_rsa_components(n, e); auto verifier = jwt::verify() .allow_algorithm(jwt::algorithm::rs256(keyPEM)) . with_claim("nonce", jwt::claim(m_oauth.nonce().toStdString())) . with_issuer(m_oidcConfig->value("issuer"_L1)).toString().toStdString()) . with_audience(std::string(clientIdentifier.data())) . leeway(60UL); verifier.verify(jwt);    qDebug() << "ID Token verified successfully";
   return true; } catch(const std::exception &e) { // 오류를 처리합니다. 또는 jwt-cpp 호출에 오류 매개변수를 전달하세요.    qWarning() << "ID Token verification failed" << e.what();
   반환 거짓; }

ID 토큰 값 읽기

ID 토큰은 점으로 구분된 헤더, 페이로드, 서명 부분으로 구성되며 ..

ID 토큰의 값을 읽는 방법은 간단합니다. 예를 들어 구조체가 있다고 가정해 보겠습니다:

struct IDToken {
    QJsonObject header;
    QJsonObject payload;
    QByteArray signature;
};

함수가 있다고 가정해 보겠습니다:

std::optional<IDToken> parseIDToken(const QString &token) const;

토큰을 추출할 수 있습니다:

if (token.isEmpty())
    return std::nullopt;

QList<QByteArray> parts = token.toLatin1().split('.');
if (parts.size() != 3)
    return std::nullopt;

QJsonParseError parsing;

QJsonDocument header = QJsonDocument::fromJson(
    QByteArray::fromBase64(parts.at(0), QByteArray::Base64UrlEncoding), &parsing);
if (parsing.error != QJsonParseError::NoError || !header.isObject())
    return std::nullopt;

QJsonDocument payload = QJsonDocument::fromJson(
    QByteArray::fromBase64(parts.at(1), QByteArray::Base64UrlEncoding), &parsing);
if (parsing.error != QJsonParseError::NoError || !payload.isObject())
    return std::nullopt;

QByteArray signature = QByteArray::fromBase64(parts.at(2), QByteArray::Base64UrlEncoding);

return IDToken{header.object(), payload.object(), signature};

경우에 따라 토큰이 내부적으로 JWT 토큰을 포함하는 JWE(JSON 웹 암호화) 로 암호화될 수 있습니다. 이 경우 먼저 토큰을 해독해야 합니다.

OpenID Connect 검색

OpenID Connect Discovery는 상호 작용하기 위해 필요한 OpenID 공급자 세부 정보를 검색하는 수단을 정의합니다. 여기에는 authorization_endpointtoken_endpoint URL과 같은 정보가 포함됩니다.

이러한 공급자 세부 정보는 애플리케이션에서 정적으로 구성할 수 있지만, 런타임에 세부 정보를 검색하면 다양한 공급자와 상호 작용할 때 더 유연하고 강력하게 사용할 수 있습니다.

검색 문서를 가져오는 방법은 간단한 HTTP GET 요청입니다. 문서는 일반적으로 https://<domain name>/.well-known/openid_configuration 에 있습니다.

m_network->get(request, this, [this](QRestReply &reply) {
    if (reply.isSuccess()) {
        if (auto doc = reply.readJson(); doc && doc->isObject())
            m_oidcConfig = doc->object(); // Store the configuration
    }
});

특히 토큰 유효성 검사를 위해 jwks_uri 필드는 현재 (공개) 보안 자격 증명에 액세스할 수 있는 링크를 제공합니다. 이를 사용하면 애플리케이션에서 이러한 자격 증명을 직접 하드코딩할 필요가 없습니다. 또한, 공급업체가 수시로 사용되는 키를 변경할 수 있으므로 최신 키를 확보하는 것이 중요하므로 키 교체에도 도움이 됩니다.

키를 얻는 방법도 마찬가지로 간단한 HTTP GET 요청으로 가능합니다:

m_network->get(request, this, [this](QRestReply &reply) {
    if (reply.isSuccess()) {
        if (auto doc = reply.readJson(); doc && doc->isObject())
            m_jwks = doc; // Use the keys later to verify tokens
    }
});

키 세트에는 일반적으로 여러 개의 키가 포함됩니다. 올바른 키는 JWT 헤더에 표시되어 있습니다(키가 올바르게 일치하도록 주의해야 하며, 키 ID( kid, 필드만 확인하는 것은 적절하지 않음).

OpenID 사용자 정보 엔드포인트

사용자 정보에 액세스하는 또 다른 방법은 OIDC 공급업체가 지원하는 경우 OpenID Connect UserInfo 엔드포인트를 사용하는 것입니다. 사용자정보의 URL은 OpenID Connect Discovery 문서의 userinfo_endpoint 필드에 있습니다.

UserInfo 엔드포인트는 ID 토큰을 사용하지 않고 액세스 토큰으로 액세스합니다. UserInfo에 액세스하는 것은 액세스 토큰으로 다른 리소스에 액세스하는 것과 유사합니다.

예를 들어 액세스 토큰을 수신하고 설정한다고 가정합니다:

QNetworkRequestFactory userInfoApi(url);
userInfoApi.setBearerToken(m_oauth.token().toLatin1());

그런 다음 UserInfo에 액세스하는 것은 HTTP GET 요청입니다:

m_network->get(userInfoApi.createRequest(), this, [this](QRestReply &reply) { if (reply.isSuccess()) { if(auto doc = reply.readJson(); doc &&  doc->isObject())            qDebug() << doc->object(); // Use the userinfo
    } });

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.