Windows uygulamalarında OAuth 2.0 uygulama

Prerequisites

  • Windows Uygulama SDK'sı Deneysel sürüm kanalı — OAuth2Manager kararlı kanalda kullanılamaz. -experimental sonekine sahip bir Microsoft.WindowsAppSDK ön sürümünü yükleyin (NuGet'te Ön sürümü dahil et seçeneğini belirleyin). Daha fazla bilgi için bkz. Geliştirme ortamınızı ayarlama.

Genel bakış

Windows Uygulama SDK'sı'deki OAuth2Manager, WinUI 3 gibi masaüstü uygulamalarının Windows üzerinde OAuth 2.0 yetkilendirmesi gerçekleştirmesini sağlar. OAuth2Manager API'sinde, güvenlikle ilgili endişeler nedeniyle örtük istek ve kaynak sahibi parola kimlik bilgileri için API'ler sağlanmamıştır. Kod Exchange (PKCE) için Proof Key ile yetkilendirme kodu verme türünü kullanın. Daha fazla bilgi için bkz . PKCE RFC.

Uyarı

OAuth2Manager herhangi bir kimlik sağlayıcısıyla (GitHub, Google, özel vb.) genel OAuth 2.0 akışları için tasarlanmıştır ve yetkilendirme adımı için her zaman sistem tarayıcısını kullanır. Özellikle Microsoft hesapları veya Microsoft Entra ID (iş/okul) hesapları ile, Windows'ta oturum açmış olan hesabınızı kullanarak ve herhangi bir tarayıcı istemine gerek kalmadan sessiz SSO (sessiz tekli oturum açma) gerçekleştirmek istiyorsanız, bunun yerine Web Hesap Yöneticisi (WAM) aracı ile birlikte MSAL.NET kullanın. Web Hesabı Yöneticisi ayrıca OAuth2Manager'ın sağlamadığı Windows Hello tümleştirme ve koşullu erişim desteği sağlar.

Windows Uygulama SDK'sı'de OAuth2Manager API'si

Windows Uygulama SDK'sı için OAuth2Manager API'si, masaüstü uygulamaları için PKCE ile OAuth 2.0 yetkilendirme kodu akışlarını işler. Windows Uygulama SDK'sı tarafından desteklenen tüm Windows platformlarında çalışır ve üçüncü taraf tarayıcı tabanlı geçici çözümler gerektirmeden tutarlı bir belirteç alma arabirimi sağlar.

OAuth2Manager, WinRT'deki WebAuthenticationBroker'dan farklıdır. Örneğin kullanıcının varsayılan tarayıcısını kullanarak OAuth 2.0 en iyi yöntemlerini daha yakından izler. API için en iyi yöntemler IETF (Internet Engineering Task Force) OAuth 2.0 Authorization Framework RFC 6749, PKCE RFC 7636 ve Native Apps rfc 8252 için OAuth 2.0'dan gelir.

OAuth 2.0 kod örnekleri

GitHub üzerinde tam bir WinUI örnek uygulaması kullanılabilir. Aşağıdaki bölümlerde, OAuth2Manager API'sini kullanan en yaygın OAuth 2.0 akışları için kod parçacıkları sağlanır.

Yetkilendirme kodu isteği

Aşağıdaki örnekte, Windows Uygulama SDK'sı'de OAuth2Manager kullanarak yetkilendirme kodu isteğinin nasıl gerçekleştirilme işlemi gösterilmektedir:

// Get the WindowId for the application window
Microsoft::UI::WindowId parentWindowId = this->AppWindow().Id();

AuthRequestParams authRequestParams = AuthRequestParams::CreateForAuthorizationCodeRequest(L"my_client_id",
   Uri(L"my-app:/oauth-callback/"));
authRequestParams.Scope(L"user:email user:birthday");

AuthRequestResult authRequestResult = co_await OAuth2Manager::RequestAuthWithParamsAsync(parentWindowId, 
   Uri(L"https://my.server.com/oauth/authorize"), authRequestParams);
if (AuthResponse authResponse = authRequestResult.Response())
{
   //To obtain the authorization code
   //authResponse.Code();

   //To obtain the access token
   DoTokenExchange(authResponse);
}
else
{
   AuthFailure authFailure = authRequestResult.Failure();
   NotifyFailure(authFailure.Error(), authFailure.ErrorDescription());
}

Erişim belirteci almak için yetkilendirme kodunu takas et.

Aşağıdaki örnekte, OAuth2Manager kullanılarak yetkilendirme kodunun bir erişim belirteci ile nasıl değiştirileceği gösterilmektedir.

PKCE kullanan genel istemciler (yerel masaüstü uygulamaları gibi) için istemci sırrı eklemeyin. Bunun yerine PKCE kod doğrulayıcısı güvenliği sağlar:

AuthResponse authResponse = authRequestResult.Response();
TokenRequestParams tokenRequestParams = TokenRequestParams::CreateForAuthorizationCodeRequest(authResponse);

// For public clients using PKCE, do not include ClientAuthentication
TokenRequestResult tokenRequestResult = co_await OAuth2Manager::RequestTokenAsync(
    Uri(L"https://my.server.com/oauth/token"), tokenRequestParams);
if (TokenResponse tokenResponse = tokenRequestResult.Response())
{
    String accessToken = tokenResponse.AccessToken();
    String tokenType = tokenResponse.TokenType();

    // RefreshToken string null/empty when not present
    if (String refreshToken = tokenResponse.RefreshToken(); !refreshToken.empty())
    {
        // ExpiresIn is zero when not present
        DateTime expires = winrt::clock::now();
        if (String expiresIn = tokenResponse.ExpiresIn(); std::stoi(expiresIn) != 0)
        {
            expires += std::chrono::seconds(static_cast<int64_t>(std::stoi(expiresIn)));
        }
        else
        {
            // Assume a duration of one hour
            expires += std::chrono::hours(1);
        }

        //Schedule a refresh of the access token
        myAppState.ScheduleRefreshAt(expires, refreshToken);
    }

    // Use the access token for resources
    DoRequestWithToken(accessToken, tokenType);
}
else
{
    TokenFailure tokenFailure = tokenRequestResult.Failure();
    NotifyFailure(tokenFailure.Error(), tokenFailure.ErrorDescription());
}

Important

Masaüstü uygulamaları genel istemcilerdir ve istemci gizli anahtarı içermemelidir. Aşağıdaki gizli istemci düzeni yalnızca kimlik bilgilerini güvenli bir şekilde depolayan sunucu tarafı bileşenleri (web uygulamaları, API'ler, arka uç hizmetleri) için geçerlidir. Yerel bir masaüstü uygulaması, istemci sırrını ele geçirilmekten koruyamaz — onun yerine yukarıda gösterilen PKCE’li açık istemci düzenini kullanın. Mimariniz belirteç alışverişi için bir istemci sırrı gerektiriyorsa, bu işlemi masaüstü uygulamasında değil, arka uç hizmetinizde gerçekleştirin.

İstemci sırrı olan gizli istemciler (web uygulamaları veya hizmetler gibi) için ClientAuthentication parametresini ekleyin:

AuthResponse authResponse = authRequestResult.Response();
TokenRequestParams tokenRequestParams = TokenRequestParams::CreateForAuthorizationCodeRequest(authResponse);
ClientAuthentication clientAuth = ClientAuthentication::CreateForBasicAuthorization(L"my_client_id",
    L"my_client_secret");

TokenRequestResult tokenRequestResult = co_await OAuth2Manager::RequestTokenAsync(
    Uri(L"https://my.server.com/oauth/token"), tokenRequestParams, clientAuth);
// Handle the response as shown in the previous example

Erişim belirtecini yenile

Aşağıdaki örnekte, OAuth2ManagerRefreshTokenAsync yöntemini kullanarak bir access belirtecinin nasıl yenilenmesi gösterilmektedir.

PKCE kullanan genel istemciler için parametresini atla ClientAuthentication :

TokenRequestParams tokenRequestParams = TokenRequestParams::CreateForRefreshToken(refreshToken);

// For public clients using PKCE, do not include ClientAuthentication
TokenRequestResult tokenRequestResult = co_await OAuth2Manager::RequestTokenAsync(
    Uri(L"https://my.server.com/oauth/token"), tokenRequestParams);
if (TokenResponse tokenResponse = tokenRequestResult.Response())
{
    UpdateToken(tokenResponse.AccessToken(), tokenResponse.TokenType(), tokenResponse.ExpiresIn());

    //Store new refresh token if present
    if (String refreshToken = tokenResponse.RefreshToken(); !refreshToken.empty())
    {
        // ExpiresIn is zero when not present
        DateTime expires = winrt::clock::now();
        if (String expiresInStr = tokenResponse.ExpiresIn(); !expiresInStr.empty())
        {
            int expiresIn = std::stoi(expiresInStr);
            if (expiresIn != 0)
            {
                expires += std::chrono::seconds(static_cast<int64_t>(expiresIn));
            }
        }
        else
        {
            // Assume a duration of one hour
            expires += std::chrono::hours(1);
        }

        //Schedule a refresh of the access token
        myAppState.ScheduleRefreshAt(expires, refreshToken);
    }
}
else
{
    TokenFailure tokenFailure = tokenRequestResult.Failure();
    NotifyFailure(tokenFailure.Error(), tokenFailure.ErrorDescription());
}

Güvenli istemciye sahip olan ve istemci gizli anahtarı bulunanlar için parametresini ekleyin:

TokenRequestParams tokenRequestParams = TokenRequestParams::CreateForRefreshToken(refreshToken);
ClientAuthentication clientAuth = ClientAuthentication::CreateForBasicAuthorization(L"my_client_id",
    L"my_client_secret");
TokenRequestResult tokenRequestResult = co_await OAuth2Manager::RequestTokenAsync(
    Uri(L"https://my.server.com/oauth/token"), tokenRequestParams, clientAuth);
// Handle the response as shown in the previous example

Yetkilendirme isteğini tamamlama

Protokol etkinleştirmesinden gelen yetkilendirme isteğini tamamlamak için uygulamanızın AppInstance.Activated olayını işlemesi gerekir. Bu olay, uygulamanızın özel yeniden yönlendirme mantığı olduğunda gereklidir. GitHub üzerinde tam bir örnek sağlanır.

Aşağıdaki kodu kullanın:

void App::OnActivated(const IActivatedEventArgs& args)
{
    if (args.Kind() == ActivationKind::Protocol)
    {
        auto protocolArgs = args.as<ProtocolActivatedEventArgs>();
        if (OAuth2Manager::CompleteAuthRequest(protocolArgs.Uri()))
        {
            TerminateCurrentProcess();
        }

        DisplayUnhandledMessageToUser();
    }
}