Trvalé další deklarace identity a tokeny od externích zprostředkovatelů v ASP.NET CorePersist additional claims and tokens from external providers in ASP.NET Core

Podle Luke LathamBy Luke Latham

Aplikace ASP.NET Core může navázat další deklarace identity a tokeny od externích zprostředkovatelů ověřování, jako je Facebook, Google, Microsoft a Twitter.An ASP.NET Core app can establish additional claims and tokens from external authentication providers, such as Facebook, Google, Microsoft, and Twitter. Každý zprostředkovatel odhalí různé informace o uživatelích na své platformě, ale vzor pro příjem a transformaci uživatelských dat do dalších deklarací identity je stejný.Each provider reveals different information about users on its platform, but the pattern for receiving and transforming user data into additional claims is the same.

Zobrazení nebo stažení ukázkového kódu (stažení)View or download sample code (how to download)

PožadavkyPrerequisites

Rozhodněte, které externí zprostředkovatelé ověřování budou v aplikaci podporovat.Decide which external authentication providers to support in the app. Pro každého poskytovatele Zaregistrujte aplikaci a Získejte ID klienta a tajný klíč klienta.For each provider, register the app and obtain a client ID and client secret. Další informace najdete v tématu Ověřování pro Facebook, Google a externí poskytovatele v ASP.NET Core.For more information, see Ověřování pro Facebook, Google a externí poskytovatele v ASP.NET Core. Ukázková aplikace používá poskytovatele ověřování Google.The sample app uses the Google authentication provider.

Nastavení ID klienta a tajného klíče klientaSet the client ID and client secret

Zprostředkovatel ověřování OAuth vytvoří vztah důvěryhodnosti s aplikací pomocí ID klienta a tajného klíče klienta.The OAuth authentication provider establishes a trust relationship with an app using a client ID and client secret. ID klienta a hodnoty tajného klíče klienta jsou vytvořeny pro aplikaci externím zprostředkovatelem ověřování při registraci aplikace u poskytovatele.Client ID and client secret values are created for the app by the external authentication provider when the app is registered with the provider. Každý externí poskytovatel, který aplikace používá, musí být nakonfigurován nezávisle s ID klienta a tajného kódu klienta.Each external provider that the app uses must be configured independently with the provider's client ID and client secret. Další informace najdete v tématech věnovaném externímu poskytovateli ověřování, které se vztahují k vašemu scénáři:For more information, see the external authentication provider topics that apply to your scenario:

Ukázková aplikace nakonfiguruje poskytovatele ověřování Google pomocí ID klienta a tajného kódu klienta poskytovaného Google:The sample app configures the Google authentication provider with a client ID and client secret provided by Google:

services.AddAuthentication().AddGoogle(options =>
{
    // Provide the Google Client ID
    options.ClientId = "XXXXXXXXXXXXXXX.apps.googleusercontent.com";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientId" "{Client ID}"

    // Provide the Google Client Secret
    options.ClientSecret = "{Client Secret}";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientSecret" "{Client Secret}"

    options.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");
    options.ClaimActions.MapJsonKey("urn:google:locale", "locale", "string");
    options.SaveTokens = true;

    options.Events.OnCreatingTicket = ctx =>
    {
        List<AuthenticationToken> tokens = ctx.Properties.GetTokens().ToList(); 

        tokens.Add(new AuthenticationToken()
        {
            Name = "TicketCreated", 
            Value = DateTime.UtcNow.ToString()
        });

        ctx.Properties.StoreTokens(tokens);

        return Task.CompletedTask;
    };
});

Vytvoření oboru ověřováníEstablish the authentication scope

Zadejte seznam oprávnění, která se mají načíst ze zprostředkovatele, zadáním Scope.Specify the list of permissions to retrieve from the provider by specifying the Scope. V následující tabulce jsou uvedeny obory ověřování pro běžné externí zprostředkovatele.Authentication scopes for common external providers appear in the following table.

ZprostředkovatelProvider OborScope
FacebookFacebook https://www.facebook.com/dialog/oauth
GoogleGoogle https://www.googleapis.com/auth/userinfo.profile
SíťovýMicrosoft https://login.microsoftonline.com/common/oauth2/v2.0/authorize
TwitterTwitter https://api.twitter.com/oauth/authenticate

V ukázkové aplikaci je obor Google userinfo.profile automaticky přidán rozhraním, když je AddGoogle na AuthenticationBuildervolána.In the sample app, Google's userinfo.profile scope is automatically added by the framework when AddGoogle is called on the AuthenticationBuilder. Pokud aplikace vyžaduje další obory, přidejte je do možností.If the app requires additional scopes, add them to the options. V následujícím příkladu je přidaný rozsah Google https://www.googleapis.com/auth/user.birthday.read, aby bylo možné načíst narozeniny uživatele:In the following example, the Google https://www.googleapis.com/auth/user.birthday.read scope is added in order to retrieve a user's birthday:

options.Scope.Add("https://www.googleapis.com/auth/user.birthday.read");

Mapování klíčů uživatelských dat a vytváření deklaracíMap user data keys and create claims

V možnostech poskytovatele určete MapJsonKey nebo MapJsonSubKey pro každý klíč nebo podklíč v datech uživatele JSON externího poskytovatele, aby se identita aplikace četla při přihlášení.In the provider's options, specify a MapJsonKey or MapJsonSubKey for each key/subkey in the external provider's JSON user data for the app identity to read on sign in. Další informace o typech deklarací identity naleznete v tématu ClaimTypes.For more information on claim types, see ClaimTypes.

Ukázková aplikace vytvoří deklarace národního prostředí (urn:google:locale) a obrázku (urn:google:picture) z locale a picture klíčů v datech uživatelů Google:The sample app creates locale (urn:google:locale) and picture (urn:google:picture) claims from the locale and picture keys in Google user data:

services.AddAuthentication().AddGoogle(options =>
{
    // Provide the Google Client ID
    options.ClientId = "XXXXXXXXXXXXXXX.apps.googleusercontent.com";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientId" "{Client ID}"

    // Provide the Google Client Secret
    options.ClientSecret = "{Client Secret}";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientSecret" "{Client Secret}"

    options.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");
    options.ClaimActions.MapJsonKey("urn:google:locale", "locale", "string");
    options.SaveTokens = true;

    options.Events.OnCreatingTicket = ctx =>
    {
        List<AuthenticationToken> tokens = ctx.Properties.GetTokens().ToList(); 

        tokens.Add(new AuthenticationToken()
        {
            Name = "TicketCreated", 
            Value = DateTime.UtcNow.ToString()
        });

        ctx.Properties.StoreTokens(tokens);

        return Task.CompletedTask;
    };
});

V Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal.ExternalLoginModel.OnPostConfirmationAsyncse do aplikace pomocí SignInAsyncpřihlašuje IdentityUser (ApplicationUser).In Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal.ExternalLoginModel.OnPostConfirmationAsync, an IdentityUser (ApplicationUser) is signed into the app with SignInAsync. Během procesu přihlašování může UserManager<TUser> ukládat deklarace identity ApplicationUser pro uživatelská data, která jsou k dispozici v Principal.During the sign in process, the UserManager<TUser> can store an ApplicationUser claims for user data available from the Principal.

V ukázkové aplikaci OnPostConfirmationAsync (account/ExternalLogin. cshtml. cs) vytvoří deklarace národního prostředí (urn:google:locale) a obrázku (urn:google:picture) pro přihlášený ApplicationUser, včetně deklarace identity pro GivenName:In the sample app, OnPostConfirmationAsync (Account/ExternalLogin.cshtml.cs) establishes the locale (urn:google:locale) and picture (urn:google:picture) claims for the signed in ApplicationUser, including a claim for GivenName:

public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    // Get the information about the user from the external login provider
    var info = await _signInManager.GetExternalLoginInfoAsync();

    if (info == null)
    {
        ErrorMessage = 
            "Error loading external login information during confirmation.";

        return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
    }

    if (ModelState.IsValid)
    {
        var user = new IdentityUser
        {
            UserName = Input.Email, 
            Email = Input.Email 
        };

        var result = await _userManager.CreateAsync(user);

        if (result.Succeeded)
        {
            result = await _userManager.AddLoginAsync(user, info);

            if (result.Succeeded)
            {
                // If they exist, add claims to the user for:
                //    Given (first) name
                //    Locale
                //    Picture
                if (info.Principal.HasClaim(c => c.Type == ClaimTypes.GivenName))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst(ClaimTypes.GivenName));
                }

                if (info.Principal.HasClaim(c => c.Type == "urn:google:locale"))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst("urn:google:locale"));
                }

                if (info.Principal.HasClaim(c => c.Type == "urn:google:picture"))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst("urn:google:picture"));
                }

                // Include the access token in the properties
                var props = new AuthenticationProperties();
                props.StoreTokens(info.AuthenticationTokens);
                props.IsPersistent = true;

                await _signInManager.SignInAsync(user, props);

                _logger.LogInformation(
                    "User created an account using {Name} provider.", 
                    info.LoginProvider);

                return LocalRedirect(returnUrl);
            }
        }

        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    LoginProvider = info.LoginProvider;
    ReturnUrl = returnUrl;
    return Page();
}

Ve výchozím nastavení jsou deklarace identity uživatele uloženy v ověřovacím souboru cookie.By default, a user's claims are stored in the authentication cookie. Pokud je soubor cookie ověřování příliš velký, může dojít k selhání aplikace z těchto důvodů:If the authentication cookie is too large, it can cause the app to fail because:

  • Prohlížeč zjistí, že hlavička souboru cookie je příliš dlouhá.The browser detects that the cookie header is too long.
  • Celková velikost požadavku je příliš velká.The overall size of the request is too large.

Pokud se pro zpracování uživatelských požadavků vyžaduje velké množství uživatelských dat:If a large amount of user data is required for processing user requests:

  • Omezte počet a velikost deklarací identity uživatelů pro zpracování žádostí jenom na to, co aplikace vyžaduje.Limit the number and size of user claims for request processing to only what the app requires.
  • Pro uložení identity mezi požadavky použijte vlastní ITicketStore pro SessionStore middlewaru ověřování souborů cookie.Use a custom ITicketStore for the Cookie Authentication Middleware's SessionStore to store identity across requests. Zachovat velké množství informací o identitě na serveru, zatímco do klienta odesílá jenom malý klíč identifikátoru relace.Preserve large quantities of identity information on the server while only sending a small session identifier key to the client.

Uložení přístupového tokenuSave the access token

SaveTokens definuje, jestli se po úspěšné autorizaci mají v AuthenticationProperties ukládat tokeny pro přístup a aktualizaci.SaveTokens defines whether access and refresh tokens should be stored in the AuthenticationProperties after a successful authorization. SaveTokens je ve výchozím nastavení nastavená na false, aby se snížila velikost konečného ověřovacího souboru cookie.SaveTokens is set to false by default to reduce the size of the final authentication cookie.

Ukázková aplikace nastaví hodnotu SaveTokens na true v GoogleOptions:The sample app sets the value of SaveTokens to true in GoogleOptions:

services.AddAuthentication().AddGoogle(options =>
{
    // Provide the Google Client ID
    options.ClientId = "XXXXXXXXXXXXXXX.apps.googleusercontent.com";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientId" "{Client ID}"

    // Provide the Google Client Secret
    options.ClientSecret = "{Client Secret}";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientSecret" "{Client Secret}"

    options.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");
    options.ClaimActions.MapJsonKey("urn:google:locale", "locale", "string");
    options.SaveTokens = true;

    options.Events.OnCreatingTicket = ctx =>
    {
        List<AuthenticationToken> tokens = ctx.Properties.GetTokens().ToList(); 

        tokens.Add(new AuthenticationToken()
        {
            Name = "TicketCreated", 
            Value = DateTime.UtcNow.ToString()
        });

        ctx.Properties.StoreTokens(tokens);

        return Task.CompletedTask;
    };
});

Když se OnPostConfirmationAsync spustí, uložte přístupový token (ExternalLoginInfo. AuthenticationTokens) od externího poskytovatele do AuthenticationProperties``ApplicationUser.When OnPostConfirmationAsync executes, store the access token (ExternalLoginInfo.AuthenticationTokens) from the external provider in the ApplicationUser's AuthenticationProperties.

Ukázková aplikace uloží přístupový token do OnPostConfirmationAsync (registrace nového uživatele) a OnGetCallbackAsync (dřív registrovaný uživatel) v účtu/ExternalLogin. cshtml. cs:The sample app saves the access token in OnPostConfirmationAsync (new user registration) and OnGetCallbackAsync (previously registered user) in Account/ExternalLogin.cshtml.cs:

public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    // Get the information about the user from the external login provider
    var info = await _signInManager.GetExternalLoginInfoAsync();

    if (info == null)
    {
        ErrorMessage = 
            "Error loading external login information during confirmation.";

        return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
    }

    if (ModelState.IsValid)
    {
        var user = new IdentityUser
        {
            UserName = Input.Email, 
            Email = Input.Email 
        };

        var result = await _userManager.CreateAsync(user);

        if (result.Succeeded)
        {
            result = await _userManager.AddLoginAsync(user, info);

            if (result.Succeeded)
            {
                // If they exist, add claims to the user for:
                //    Given (first) name
                //    Locale
                //    Picture
                if (info.Principal.HasClaim(c => c.Type == ClaimTypes.GivenName))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst(ClaimTypes.GivenName));
                }

                if (info.Principal.HasClaim(c => c.Type == "urn:google:locale"))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst("urn:google:locale"));
                }

                if (info.Principal.HasClaim(c => c.Type == "urn:google:picture"))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst("urn:google:picture"));
                }

                // Include the access token in the properties
                var props = new AuthenticationProperties();
                props.StoreTokens(info.AuthenticationTokens);
                props.IsPersistent = true;

                await _signInManager.SignInAsync(user, props);

                _logger.LogInformation(
                    "User created an account using {Name} provider.", 
                    info.LoginProvider);

                return LocalRedirect(returnUrl);
            }
        }

        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    LoginProvider = info.LoginProvider;
    ReturnUrl = returnUrl;
    return Page();
}

Postup přidání dalších vlastních tokenůHow to add additional custom tokens

Chcete-li předvést, jak přidat vlastní token, který je uložen jako součást SaveTokens, ukázková aplikace přidá AuthenticationToken s aktuálním DateTime pro AuthenticationToken.Name TicketCreated:To demonstrate how to add a custom token, which is stored as part of SaveTokens, the sample app adds an AuthenticationToken with the current DateTime for an AuthenticationToken.Name of TicketCreated:

services.AddAuthentication().AddGoogle(options =>
{
    // Provide the Google Client ID
    options.ClientId = "XXXXXXXXXXXXXXX.apps.googleusercontent.com";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientId" "{Client ID}"

    // Provide the Google Client Secret
    options.ClientSecret = "{Client Secret}";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientSecret" "{Client Secret}"

    options.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");
    options.ClaimActions.MapJsonKey("urn:google:locale", "locale", "string");
    options.SaveTokens = true;

    options.Events.OnCreatingTicket = ctx =>
    {
        List<AuthenticationToken> tokens = ctx.Properties.GetTokens().ToList(); 

        tokens.Add(new AuthenticationToken()
        {
            Name = "TicketCreated", 
            Value = DateTime.UtcNow.ToString()
        });

        ctx.Properties.StoreTokens(tokens);

        return Task.CompletedTask;
    };
});

Vytváření a přidávání deklarací identityCreating and adding claims

Rozhraní poskytuje běžné akce a metody rozšíření pro vytváření a přidávání deklarací identity do kolekce.The framework provides common actions and extension methods for creating and adding claims to the collection. Další informace najdete v tématu ClaimActionCollectionMapExtensions a ClaimActionCollectionUniqueExtensions.For more information, see the ClaimActionCollectionMapExtensions and ClaimActionCollectionUniqueExtensions.

Uživatelé mohou definovat vlastní akce odvozením z ClaimAction a implementací abstraktních Runch metod.Users can define custom actions by deriving from ClaimAction and implementing the abstract Run method.

Další informace najdete v tématu Microsoft.AspNetCore.Authentication.OAuth.Claims.For more information, see Microsoft.AspNetCore.Authentication.OAuth.Claims.

Odebrání akcí a deklarací identityRemoval of claim actions and claims

ClaimActionCollection. Remove (String) odebere z kolekce všechny akce deklarací identity pro daný ClaimType.ClaimActionCollection.Remove(String) removes all claim actions for the given ClaimType from the collection. ClaimActionCollectionMapExtensions. DeleteClaim (ClaimActionCollection, String) odstraní deklaraci identity daného ClaimType z identity.ClaimActionCollectionMapExtensions.DeleteClaim(ClaimActionCollection, String) deletes a claim of the given ClaimType from the identity. DeleteClaim se primárně používá s OpenID Connect (OIDC) k odebrání deklarací generovaných protokolem.DeleteClaim is primarily used with OpenID Connect (OIDC) to remove protocol-generated claims.

Výstup ukázkové aplikaceSample app output

User Claims

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
    9b342344f-7aab-43c2-1ac1-ba75912ca999
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
    someone@gmail.com
AspNet.Identity.SecurityStamp
    7D4312MOWRYYBFI1KXRPHGOSTBVWSFDE
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
    Judy
urn:google:locale
    en
urn:google:picture
    https://lh4.googleusercontent.com/-XXXXXX/XXXXXX/XXXXXX/XXXXXX/photo.jpg

Authentication Properties

.Token.access_token
    yc23.AlvoZqz56...1lxltXV7D-ZWP9
.Token.token_type
    Bearer
.Token.expires_at
    2019-04-11T22:14:51.0000000+00:00
.Token.TicketCreated
    4/11/2019 9:14:52 PM
.TokenNames
    access_token;token_type;expires_at;TicketCreated
.persistent
.issued
    Thu, 11 Apr 2019 20:51:06 GMT
.expires
    Thu, 25 Apr 2019 20:51:06 GMT

Vpřed žádost o informace o proxy serveru nebo nástroj pro vyrovnávání zatíženíForward request information with a proxy or load balancer

Pokud je aplikace nasazena za proxy server nebo nástroje pro vyrovnávání zatížení, některé z původní informace o požadavku může být přeposílán aplikace v záhlaví požadavku.If the app is deployed behind a proxy server or load balancer, some of the original request information might be forwarded to the app in request headers. Tyto informace obvykle obsahuje schéma požadavku zabezpečení (https), hostitele a IP adresu klienta.This information usually includes the secure request scheme (https), host, and client IP address. Aplikace si automaticky tyto hlavičky žádosti mohli objevit a používat původní informace o žádostech.Apps don't automatically read these request headers to discover and use the original request information.

Schéma se používá při generování odkazů, které má vliv na tok ověřování u externích poskytovatelů.The scheme is used in link generation that affects the authentication flow with external providers. Zabezpečený režim ztráty (https) výsledkem generování adresy URL pro přesměrování nesprávné nezabezpečené aplikace.Losing the secure scheme (https) results in the app generating incorrect insecure redirect URLs.

Předané Middleware záhlaví využívat k zpřístupňování původní informace o požadavku do aplikace pro zpracování požadavku.Use Forwarded Headers Middleware to make the original request information available to the app for request processing.

Další informace naleznete v tématu Konfigurace ASP.NET Core pro práci se servery proxy a nástroji pro vyrovnávání zatížení.For more information, see Konfigurace ASP.NET Core pro práci se servery proxy a nástroji pro vyrovnávání zatížení.

Aplikace ASP.NET Core může navázat další deklarace identity a tokeny od externích zprostředkovatelů ověřování, jako je Facebook, Google, Microsoft a Twitter.An ASP.NET Core app can establish additional claims and tokens from external authentication providers, such as Facebook, Google, Microsoft, and Twitter. Každý zprostředkovatel odhalí různé informace o uživatelích na své platformě, ale vzor pro příjem a transformaci uživatelských dat do dalších deklarací identity je stejný.Each provider reveals different information about users on its platform, but the pattern for receiving and transforming user data into additional claims is the same.

Zobrazení nebo stažení ukázkového kódu (stažení)View or download sample code (how to download)

PožadavkyPrerequisites

Rozhodněte, které externí zprostředkovatelé ověřování budou v aplikaci podporovat.Decide which external authentication providers to support in the app. Pro každého poskytovatele Zaregistrujte aplikaci a Získejte ID klienta a tajný klíč klienta.For each provider, register the app and obtain a client ID and client secret. Další informace najdete v tématu Ověřování pro Facebook, Google a externí poskytovatele v ASP.NET Core.For more information, see Ověřování pro Facebook, Google a externí poskytovatele v ASP.NET Core. Ukázková aplikace používá poskytovatele ověřování Google.The sample app uses the Google authentication provider.

Nastavení ID klienta a tajného klíče klientaSet the client ID and client secret

Zprostředkovatel ověřování OAuth vytvoří vztah důvěryhodnosti s aplikací pomocí ID klienta a tajného klíče klienta.The OAuth authentication provider establishes a trust relationship with an app using a client ID and client secret. ID klienta a hodnoty tajného klíče klienta jsou vytvořeny pro aplikaci externím zprostředkovatelem ověřování při registraci aplikace u poskytovatele.Client ID and client secret values are created for the app by the external authentication provider when the app is registered with the provider. Každý externí poskytovatel, který aplikace používá, musí být nakonfigurován nezávisle s ID klienta a tajného kódu klienta.Each external provider that the app uses must be configured independently with the provider's client ID and client secret. Další informace najdete v tématech věnovaném externímu poskytovateli ověřování, které se vztahují k vašemu scénáři:For more information, see the external authentication provider topics that apply to your scenario:

Ukázková aplikace nakonfiguruje poskytovatele ověřování Google pomocí ID klienta a tajného kódu klienta poskytovaného Google:The sample app configures the Google authentication provider with a client ID and client secret provided by Google:

services.AddAuthentication().AddGoogle(options =>
{
    // Provide the Google Client ID
    options.ClientId = "XXXXXXXXXXXXXXX.apps.googleusercontent.com";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientId" "{Client ID}"

    // Provide the Google Client Secret
    options.ClientSecret = "{Client Secret}";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientSecret" "{Client Secret}"

    options.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");
    options.ClaimActions.MapJsonKey("urn:google:locale", "locale", "string");
    options.SaveTokens = true;

    options.Events.OnCreatingTicket = ctx =>
    {
        List<AuthenticationToken> tokens = ctx.Properties.GetTokens().ToList(); 

        tokens.Add(new AuthenticationToken()
        {
            Name = "TicketCreated", 
            Value = DateTime.UtcNow.ToString()
        });

        ctx.Properties.StoreTokens(tokens);

        return Task.CompletedTask;
    };
});

Vytvoření oboru ověřováníEstablish the authentication scope

Zadejte seznam oprávnění, která se mají načíst ze zprostředkovatele, zadáním Scope.Specify the list of permissions to retrieve from the provider by specifying the Scope. V následující tabulce jsou uvedeny obory ověřování pro běžné externí zprostředkovatele.Authentication scopes for common external providers appear in the following table.

ZprostředkovatelProvider OborScope
FacebookFacebook https://www.facebook.com/dialog/oauth
GoogleGoogle https://www.googleapis.com/auth/userinfo.profile
SíťovýMicrosoft https://login.microsoftonline.com/common/oauth2/v2.0/authorize
TwitterTwitter https://api.twitter.com/oauth/authenticate

V ukázkové aplikaci je obor Google userinfo.profile automaticky přidán rozhraním, když je AddGoogle na AuthenticationBuildervolána.In the sample app, Google's userinfo.profile scope is automatically added by the framework when AddGoogle is called on the AuthenticationBuilder. Pokud aplikace vyžaduje další obory, přidejte je do možností.If the app requires additional scopes, add them to the options. V následujícím příkladu je přidaný rozsah Google https://www.googleapis.com/auth/user.birthday.read, aby bylo možné načíst narozeniny uživatele:In the following example, the Google https://www.googleapis.com/auth/user.birthday.read scope is added in order to retrieve a user's birthday:

options.Scope.Add("https://www.googleapis.com/auth/user.birthday.read");

Mapování klíčů uživatelských dat a vytváření deklaracíMap user data keys and create claims

V možnostech poskytovatele určete MapJsonKey nebo MapJsonSubKey pro každý klíč nebo podklíč v datech uživatele JSON externího poskytovatele, aby se identita aplikace četla při přihlášení.In the provider's options, specify a MapJsonKey or MapJsonSubKey for each key/subkey in the external provider's JSON user data for the app identity to read on sign in. Další informace o typech deklarací identity naleznete v tématu ClaimTypes.For more information on claim types, see ClaimTypes.

Ukázková aplikace vytvoří deklarace národního prostředí (urn:google:locale) a obrázku (urn:google:picture) z locale a picture klíčů v datech uživatelů Google:The sample app creates locale (urn:google:locale) and picture (urn:google:picture) claims from the locale and picture keys in Google user data:

services.AddAuthentication().AddGoogle(options =>
{
    // Provide the Google Client ID
    options.ClientId = "XXXXXXXXXXXXXXX.apps.googleusercontent.com";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientId" "{Client ID}"

    // Provide the Google Client Secret
    options.ClientSecret = "{Client Secret}";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientSecret" "{Client Secret}"

    options.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");
    options.ClaimActions.MapJsonKey("urn:google:locale", "locale", "string");
    options.SaveTokens = true;

    options.Events.OnCreatingTicket = ctx =>
    {
        List<AuthenticationToken> tokens = ctx.Properties.GetTokens().ToList(); 

        tokens.Add(new AuthenticationToken()
        {
            Name = "TicketCreated", 
            Value = DateTime.UtcNow.ToString()
        });

        ctx.Properties.StoreTokens(tokens);

        return Task.CompletedTask;
    };
});

V Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal.ExternalLoginModel.OnPostConfirmationAsyncse do aplikace pomocí SignInAsyncpřihlašuje IdentityUser (ApplicationUser).In Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal.ExternalLoginModel.OnPostConfirmationAsync, an IdentityUser (ApplicationUser) is signed into the app with SignInAsync. Během procesu přihlašování může UserManager<TUser> ukládat deklarace identity ApplicationUser pro uživatelská data, která jsou k dispozici v Principal.During the sign in process, the UserManager<TUser> can store an ApplicationUser claims for user data available from the Principal.

V ukázkové aplikaci OnPostConfirmationAsync (account/ExternalLogin. cshtml. cs) vytvoří deklarace národního prostředí (urn:google:locale) a obrázku (urn:google:picture) pro přihlášený ApplicationUser, včetně deklarace identity pro GivenName:In the sample app, OnPostConfirmationAsync (Account/ExternalLogin.cshtml.cs) establishes the locale (urn:google:locale) and picture (urn:google:picture) claims for the signed in ApplicationUser, including a claim for GivenName:

public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    // Get the information about the user from the external login provider
    var info = await _signInManager.GetExternalLoginInfoAsync();

    if (info == null)
    {
        ErrorMessage = 
            "Error loading external login information during confirmation.";

        return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
    }

    if (ModelState.IsValid)
    {
        var user = new IdentityUser
        {
            UserName = Input.Email, 
            Email = Input.Email 
        };

        var result = await _userManager.CreateAsync(user);

        if (result.Succeeded)
        {
            result = await _userManager.AddLoginAsync(user, info);

            if (result.Succeeded)
            {
                // If they exist, add claims to the user for:
                //    Given (first) name
                //    Locale
                //    Picture
                if (info.Principal.HasClaim(c => c.Type == ClaimTypes.GivenName))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst(ClaimTypes.GivenName));
                }

                if (info.Principal.HasClaim(c => c.Type == "urn:google:locale"))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst("urn:google:locale"));
                }

                if (info.Principal.HasClaim(c => c.Type == "urn:google:picture"))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst("urn:google:picture"));
                }

                // Include the access token in the properties
                var props = new AuthenticationProperties();
                props.StoreTokens(info.AuthenticationTokens);
                props.IsPersistent = true;

                await _signInManager.SignInAsync(user, props);

                _logger.LogInformation(
                    "User created an account using {Name} provider.", 
                    info.LoginProvider);

                return LocalRedirect(returnUrl);
            }
        }

        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    LoginProvider = info.LoginProvider;
    ReturnUrl = returnUrl;
    return Page();
}

Ve výchozím nastavení jsou deklarace identity uživatele uloženy v ověřovacím souboru cookie.By default, a user's claims are stored in the authentication cookie. Pokud je soubor cookie ověřování příliš velký, může dojít k selhání aplikace z těchto důvodů:If the authentication cookie is too large, it can cause the app to fail because:

  • Prohlížeč zjistí, že hlavička souboru cookie je příliš dlouhá.The browser detects that the cookie header is too long.
  • Celková velikost požadavku je příliš velká.The overall size of the request is too large.

Pokud se pro zpracování uživatelských požadavků vyžaduje velké množství uživatelských dat:If a large amount of user data is required for processing user requests:

  • Omezte počet a velikost deklarací identity uživatelů pro zpracování žádostí jenom na to, co aplikace vyžaduje.Limit the number and size of user claims for request processing to only what the app requires.
  • Pro uložení identity mezi požadavky použijte vlastní ITicketStore pro SessionStore middlewaru ověřování souborů cookie.Use a custom ITicketStore for the Cookie Authentication Middleware's SessionStore to store identity across requests. Zachovat velké množství informací o identitě na serveru, zatímco do klienta odesílá jenom malý klíč identifikátoru relace.Preserve large quantities of identity information on the server while only sending a small session identifier key to the client.

Uložení přístupového tokenuSave the access token

SaveTokens definuje, jestli se po úspěšné autorizaci mají v AuthenticationProperties ukládat tokeny pro přístup a aktualizaci.SaveTokens defines whether access and refresh tokens should be stored in the AuthenticationProperties after a successful authorization. SaveTokens je ve výchozím nastavení nastavená na false, aby se snížila velikost konečného ověřovacího souboru cookie.SaveTokens is set to false by default to reduce the size of the final authentication cookie.

Ukázková aplikace nastaví hodnotu SaveTokens na true v GoogleOptions:The sample app sets the value of SaveTokens to true in GoogleOptions:

services.AddAuthentication().AddGoogle(options =>
{
    // Provide the Google Client ID
    options.ClientId = "XXXXXXXXXXXXXXX.apps.googleusercontent.com";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientId" "{Client ID}"

    // Provide the Google Client Secret
    options.ClientSecret = "{Client Secret}";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientSecret" "{Client Secret}"

    options.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");
    options.ClaimActions.MapJsonKey("urn:google:locale", "locale", "string");
    options.SaveTokens = true;

    options.Events.OnCreatingTicket = ctx =>
    {
        List<AuthenticationToken> tokens = ctx.Properties.GetTokens().ToList(); 

        tokens.Add(new AuthenticationToken()
        {
            Name = "TicketCreated", 
            Value = DateTime.UtcNow.ToString()
        });

        ctx.Properties.StoreTokens(tokens);

        return Task.CompletedTask;
    };
});

Když se OnPostConfirmationAsync spustí, uložte přístupový token (ExternalLoginInfo. AuthenticationTokens) od externího poskytovatele do AuthenticationProperties``ApplicationUser.When OnPostConfirmationAsync executes, store the access token (ExternalLoginInfo.AuthenticationTokens) from the external provider in the ApplicationUser's AuthenticationProperties.

Ukázková aplikace uloží přístupový token do OnPostConfirmationAsync (registrace nového uživatele) a OnGetCallbackAsync (dřív registrovaný uživatel) v účtu/ExternalLogin. cshtml. cs:The sample app saves the access token in OnPostConfirmationAsync (new user registration) and OnGetCallbackAsync (previously registered user) in Account/ExternalLogin.cshtml.cs:

public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    // Get the information about the user from the external login provider
    var info = await _signInManager.GetExternalLoginInfoAsync();

    if (info == null)
    {
        ErrorMessage = 
            "Error loading external login information during confirmation.";

        return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
    }

    if (ModelState.IsValid)
    {
        var user = new IdentityUser
        {
            UserName = Input.Email, 
            Email = Input.Email 
        };

        var result = await _userManager.CreateAsync(user);

        if (result.Succeeded)
        {
            result = await _userManager.AddLoginAsync(user, info);

            if (result.Succeeded)
            {
                // If they exist, add claims to the user for:
                //    Given (first) name
                //    Locale
                //    Picture
                if (info.Principal.HasClaim(c => c.Type == ClaimTypes.GivenName))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst(ClaimTypes.GivenName));
                }

                if (info.Principal.HasClaim(c => c.Type == "urn:google:locale"))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst("urn:google:locale"));
                }

                if (info.Principal.HasClaim(c => c.Type == "urn:google:picture"))
                {
                    await _userManager.AddClaimAsync(user, 
                        info.Principal.FindFirst("urn:google:picture"));
                }

                // Include the access token in the properties
                var props = new AuthenticationProperties();
                props.StoreTokens(info.AuthenticationTokens);
                props.IsPersistent = true;

                await _signInManager.SignInAsync(user, props);

                _logger.LogInformation(
                    "User created an account using {Name} provider.", 
                    info.LoginProvider);

                return LocalRedirect(returnUrl);
            }
        }

        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    LoginProvider = info.LoginProvider;
    ReturnUrl = returnUrl;
    return Page();
}

Postup přidání dalších vlastních tokenůHow to add additional custom tokens

Chcete-li předvést, jak přidat vlastní token, který je uložen jako součást SaveTokens, ukázková aplikace přidá AuthenticationToken s aktuálním DateTime pro AuthenticationToken.Name TicketCreated:To demonstrate how to add a custom token, which is stored as part of SaveTokens, the sample app adds an AuthenticationToken with the current DateTime for an AuthenticationToken.Name of TicketCreated:

services.AddAuthentication().AddGoogle(options =>
{
    // Provide the Google Client ID
    options.ClientId = "XXXXXXXXXXXXXXX.apps.googleusercontent.com";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientId" "{Client ID}"

    // Provide the Google Client Secret
    options.ClientSecret = "{Client Secret}";
    // Register with User Secrets using:
    // dotnet user-secrets set "Authentication:Google:ClientSecret" "{Client Secret}"

    options.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");
    options.ClaimActions.MapJsonKey("urn:google:locale", "locale", "string");
    options.SaveTokens = true;

    options.Events.OnCreatingTicket = ctx =>
    {
        List<AuthenticationToken> tokens = ctx.Properties.GetTokens().ToList(); 

        tokens.Add(new AuthenticationToken()
        {
            Name = "TicketCreated", 
            Value = DateTime.UtcNow.ToString()
        });

        ctx.Properties.StoreTokens(tokens);

        return Task.CompletedTask;
    };
});

Vytváření a přidávání deklarací identityCreating and adding claims

Rozhraní poskytuje běžné akce a metody rozšíření pro vytváření a přidávání deklarací identity do kolekce.The framework provides common actions and extension methods for creating and adding claims to the collection. Další informace najdete v tématu ClaimActionCollectionMapExtensions a ClaimActionCollectionUniqueExtensions.For more information, see the ClaimActionCollectionMapExtensions and ClaimActionCollectionUniqueExtensions.

Uživatelé mohou definovat vlastní akce odvozením z ClaimAction a implementací abstraktních Runch metod.Users can define custom actions by deriving from ClaimAction and implementing the abstract Run method.

Další informace najdete v tématu Microsoft.AspNetCore.Authentication.OAuth.Claims.For more information, see Microsoft.AspNetCore.Authentication.OAuth.Claims.

Odebrání akcí a deklarací identityRemoval of claim actions and claims

ClaimActionCollection. Remove (String) odebere z kolekce všechny akce deklarací identity pro daný ClaimType.ClaimActionCollection.Remove(String) removes all claim actions for the given ClaimType from the collection. ClaimActionCollectionMapExtensions. DeleteClaim (ClaimActionCollection, String) odstraní deklaraci identity daného ClaimType z identity.ClaimActionCollectionMapExtensions.DeleteClaim(ClaimActionCollection, String) deletes a claim of the given ClaimType from the identity. DeleteClaim se primárně používá s OpenID Connect (OIDC) k odebrání deklarací generovaných protokolem.DeleteClaim is primarily used with OpenID Connect (OIDC) to remove protocol-generated claims.

Výstup ukázkové aplikaceSample app output

User Claims

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
    9b342344f-7aab-43c2-1ac1-ba75912ca999
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
    someone@gmail.com
AspNet.Identity.SecurityStamp
    7D4312MOWRYYBFI1KXRPHGOSTBVWSFDE
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
    Judy
urn:google:locale
    en
urn:google:picture
    https://lh4.googleusercontent.com/-XXXXXX/XXXXXX/XXXXXX/XXXXXX/photo.jpg

Authentication Properties

.Token.access_token
    yc23.AlvoZqz56...1lxltXV7D-ZWP9
.Token.token_type
    Bearer
.Token.expires_at
    2019-04-11T22:14:51.0000000+00:00
.Token.TicketCreated
    4/11/2019 9:14:52 PM
.TokenNames
    access_token;token_type;expires_at;TicketCreated
.persistent
.issued
    Thu, 11 Apr 2019 20:51:06 GMT
.expires
    Thu, 25 Apr 2019 20:51:06 GMT

Vpřed žádost o informace o proxy serveru nebo nástroj pro vyrovnávání zatíženíForward request information with a proxy or load balancer

Pokud je aplikace nasazena za proxy server nebo nástroje pro vyrovnávání zatížení, některé z původní informace o požadavku může být přeposílán aplikace v záhlaví požadavku.If the app is deployed behind a proxy server or load balancer, some of the original request information might be forwarded to the app in request headers. Tyto informace obvykle obsahuje schéma požadavku zabezpečení (https), hostitele a IP adresu klienta.This information usually includes the secure request scheme (https), host, and client IP address. Aplikace si automaticky tyto hlavičky žádosti mohli objevit a používat původní informace o žádostech.Apps don't automatically read these request headers to discover and use the original request information.

Schéma se používá při generování odkazů, které má vliv na tok ověřování u externích poskytovatelů.The scheme is used in link generation that affects the authentication flow with external providers. Zabezpečený režim ztráty (https) výsledkem generování adresy URL pro přesměrování nesprávné nezabezpečené aplikace.Losing the secure scheme (https) results in the app generating incorrect insecure redirect URLs.

Předané Middleware záhlaví využívat k zpřístupňování původní informace o požadavku do aplikace pro zpracování požadavku.Use Forwarded Headers Middleware to make the original request information available to the app for request processing.

Další informace naleznete v tématu Konfigurace ASP.NET Core pro práci se servery proxy a nástroji pro vyrovnávání zatížení.For more information, see Konfigurace ASP.NET Core pro práci se servery proxy a nástroji pro vyrovnávání zatížení.

Další materiály a zdroje informacíAdditional resources

  • dotnet/AspNetCore Engineering SocialSample app – je propojená ukázková aplikace na master technické větvi úložiště GitHub/AspNetCore .dotnet/AspNetCore engineering SocialSample app – The linked sample app is on the dotnet/AspNetCore GitHub repo's master engineering branch. Větev master obsahuje kód v části aktivní vývoj pro další verzi ASP.NET Core.The master branch contains code under active development for the next release of ASP.NET Core. Pokud chcete zobrazit verzi ukázkové aplikace pro vydanou verzi ASP.NET Core, použijte rozevírací seznam větev a vyberte větev vydané verze (například release/{X.Y}).To see a version of the sample app for a released version of ASP.NET Core, use the Branch drop down list to select a release branch (for example release/{X.Y}).