Kiracı kaydolma ve eklemeTenant sign-up and onboarding

GitHub Örnek kodGitHub Sample code

Bu makalede nasıl uygulanacağı bir kaydolma müşteri kuruluş uygulamanız için kayıt sağlayan çok müşterili uygulamalarda işlem.This article describes how to implement a sign-up process in a multitenant application, which allows a customer to sign up their organization for your application.

Kaydolma işlemini uygulamak için birkaç nedeni vardır:There are several reasons to implement a sign-up process:

  • Bir AD Yönetici uygulamayı kullanmak Müşteri'nin tüm kuruluş için onayı izin verir.Allow an AD admin to consent for the customer's entire organization to use the application.
  • Kredi kartıyla ödeme veya diğer müşteri bilgilerini toplayın.Collect credit card payment or other customer information.
  • Uygulamanızın ihtiyaç duyduğu tüm Kiracı başına tek seferlik Kurulum gerçekleştirin.Perform any one-time per-tenant setup needed by your application.

Azure AD ile kimlik doğrulamak için bir uygulama kullanıcının dizine erişim gerekir.In order to authenticate with Azure AD, an application needs access to the user's directory. En azından, uygulamanın kullanıcı profilini okuma izni gerekir.At a minimum, the application needs permission to read the user's profile. İlk kez bir kullanıcı oturum açar ve Azure AD istenen izinler listeleyen bir onay sayfası gösterilir.The first time that a user signs in, Azure AD shows a consent page that lists the permissions being requested. Tıklayarak kabul, kullanıcının uygulamaya izin verir.By clicking Accept, the user grants permission to the application.

Varsayılan olarak, kullanıcı başına esasına göre izin verilir.By default, consent is granted on a per-user basis. Açan her kullanıcı onay sayfası görür.Every user who signs in sees the consent page. Ancak, Azure AD ayrıca destekler yönetici onayı, kuruluşun tamamına için onay bir AD Yöneticisi sağlar.However, Azure AD also supports admin consent, which allows an AD administrator to consent for an entire organization.

Yönetici onay akışı kullanıldığında, onay sayfası AD Yöneticisi tüm Kiracı adına izin verilmesi gerektiğini ifade eder:When the admin consent flow is used, the consent page states that the AD admin is granting permission on behalf of the entire tenant:

Yönetici onay istemi

Yönetici tıkladıktan sonra kabul, diğer kullanıcılar aynı kiracıda oturum açabilir ve Azure AD, izin ekranı atlar.After the admin clicks Accept, other users within the same tenant can sign in, and Azure AD will skip the consent screen.

Tüm kuruluş adına izin verdiği için yalnızca bir AD Yöneticisi yönetici onayı verebilir.Only an AD administrator can give admin consent, because it grants permission on behalf of the entire organization. Azure AD, yönetici olmayan bir yönetici onayı akışı kimlik doğrulaması çalışırsa, bir hata görüntüler:If a non-administrator tries to authenticate with the admin consent flow, Azure AD displays an error:

İzin hatası

Uygulama daha sonraki bir noktada ek izinler gerekiyorsa, müşteri yeniden kaydolmayı ve güncelleştirilmiş izni onayı gerekir.If the application requires additional permissions at a later point, the customer will need to sign up again and consent to the updated permissions.

Kiracı kaydı uygulamaImplementing tenant sign-up

İçin [Tailspin Surveys] Tailspin uygulama kaydolma işlemi için birkaç gereksinim tanımladık:For the Tailspin Surveys application, we defined several requirements for the sign-up process:

  • Kullanıcılar oturum açabilmeniz için önce bir kiracı kaydolmalısınız.A tenant must sign up before users can sign in.
  • Kayıt, yönetici onayı akışı kullanır.Sign-up uses the admin consent flow.
  • Kaydolma kullanıcının Kiracı uygulama veritabanına ekler.Sign-up adds the user's tenant to the application database.
  • Bir kiracı kaydolursa sonra uygulama ekleme sayfası gösterilir.After a tenant signs up, the application shows an onboarding page.

Bu bölümde, kayıt işlemini kararlılığımızın alacağız.In this section, we'll walk through our implementation of the sign-up process. Önemli olduğu, "kaydolma" ve "oturum açma" anlamak için bir uygulama kavramdır.It's important to understand that "sign up" versus "sign in" is an application concept. Kimlik doğrulama akışı sırasında Azure AD kendiliğinden kullanıcı kaydolan aşamasındayız olup olmadığını bilmez.During the authentication flow, Azure AD does not inherently know whether the user is in process of signing up. Bu bağlam izlemek için uygulamaya aittir.It's up to the application to keep track of the context.

Anonim kullanıcı Surveys uygulamasını ziyaret ettiğinde gösterilen iki düğme, oturum açmak için diğeri "şirketiniz kaydetmek için" kullanıcı olduğunu (Kaydol).When an anonymous user visits the Surveys application, the user is shown two buttons, one to sign in, and one to "enroll your company" (sign up).

Uygulama kayıt sayfası

Bu düğme eylemleri çağırmak AccountController sınıfı.These buttons invoke actions in the AccountController class.

SignIn Eylem döndürür bir ChallengeResult, kimlik doğrulama uç noktası için yeniden yönlendirmek Openıd Connect ara yazılımını neden olur.The SignIn action returns a ChallengeResult, which causes the OpenID Connect middleware to redirect to the authentication endpoint. Tetikleyici ASP.NET Core kimlik doğrulaması için varsayılan yolu budur.This is the default way to trigger authentication in ASP.NET Core.

[AllowAnonymous]
public IActionResult SignIn()
{
    return new ChallengeResult(
        OpenIdConnectDefaults.AuthenticationScheme,
        new AuthenticationProperties
        {
            IsPersistent = true,
            RedirectUri = Url.Action("SignInCallback", "Account")
        });
}

Artık karşılaştırma SignUp eylem:Now compare the SignUp action:

[AllowAnonymous]
public IActionResult SignUp()
{
    var state = new Dictionary<string, string> { { "signup", "true" }};
    return new ChallengeResult(
        OpenIdConnectDefaults.AuthenticationScheme,
        new AuthenticationProperties(state)
        {
            RedirectUri = Url.Action(nameof(SignUpCallback), "Account")
        });
}

Gibi SignIn, SignUp eylem ayrıca döndürür bir ChallengeResult.Like SignIn, the SignUp action also returns a ChallengeResult. Ancak bu kez, durum bilgilerini bir parçasını eklediğimiz AuthenticationProperties içinde ChallengeResult:But this time, we add a piece of state information to the AuthenticationProperties in the ChallengeResult:

  • Kaydol: Kullanıcı kaydolma işleminin başlatıldığını belirten bir Boole bayrağı.signup: A Boolean flag, indicating that the user has started the sign-up process.

Durum bilgileri AuthenticationProperties Openıd Connect eklenen durumu sırasında kimlik doğrulaması akışı gelişlerin yuvarlak parametresi.The state information in AuthenticationProperties gets added to the OpenID Connect state parameter, which round trips during the authentication flow.

Durum parametresi

Kullanıcının Azure AD'de kimlik doğrulaması yapar ve yeniden uygulamaya yönlendirilir sonra kimlik doğrulaması bileti durumunu içerir.After the user authenticates in Azure AD and gets redirected back to the application, the authentication ticket contains the state. "Signup" değeri tüm kimlik doğrulama akışı devam ederse emin olmak için bu olgu kullanıyoruz.We are using this fact to make sure the "signup" value persists across the entire authentication flow.

Azure AD'de kimlik doğrulama isteği sorgu dizesinde "istemi" parametre ekleyerek yönetici onayı akış tetiklenir:In Azure AD, the admin consent flow is triggered by adding a "prompt" parameter to the query string in the authentication request:

/authorize?prompt=admin_consent&...

Surveys uygulamasını sırasında istemi ekler RedirectToAuthenticationEndpoint olay.The Surveys application adds the prompt during the RedirectToAuthenticationEndpoint event. Bu olay, doğru ara yazılım kimlik doğrulaması uç noktaya yönlendiren önce çağrılır.This event is called right before the middleware redirects to the authentication endpoint.

public override Task RedirectToAuthenticationEndpoint(RedirectContext context)
{
    if (context.IsSigningUp())
    {
        context.ProtocolMessage.Prompt = "admin_consent";
    }

    _logger.RedirectToIdentityProvider();
    return Task.FromResult(0);
}

Ayar ProtocolMessage.Prompt kimlik doğrulama isteğini "istemi" parametre eklemek için bir ara yazılım söyler.Setting ProtocolMessage.Prompt tells the middleware to add the "prompt" parameter to the authentication request.

İstemi yalnızca kayıt sırasında gerekli olduğunu unutmayın.Note that the prompt is only needed during sign-up. Normal oturum açma, içermemelidir.Regular sign-in should not include it. Bunlar arasında ayrım yapmak için biz denetle signup kimlik doğrulama durumu değeri.To distinguish between them, we check for the signup value in the authentication state. Aşağıdaki uzantı yöntemi, bu koşulu denetler:The following extension method checks for this condition:

internal static bool IsSigningUp(this BaseControlContext context)
{
    Guard.ArgumentNotNull(context, nameof(context));

    string signupValue;
    // Check the HTTP context and convert to string
    if ((context.Ticket == null) ||
        (!context.Ticket.Properties.Items.TryGetValue("signup", out signupValue)))
    {
        return false;
    }

    // We have found the value, so see if it's valid
    bool isSigningUp;
    if (!bool.TryParse(signupValue, out isSigningUp))
    {
        // The value for signup is not a valid boolean, throw

        throw new InvalidOperationException($"'{signupValue}' is an invalid boolean value");
    }

    return isSigningUp;
}

Bir kiracı kaydetmeRegistering a tenant

Surveys uygulamasını her Kiracı hakkında bazı bilgiler ve kullanıcı uygulaması veritabanında depolar.The Surveys application stores some information about each tenant and user in the application database.

Kiracı tablo

Kiracı tablosunda IssuerValue kiracının verenin talep değeridir.In the Tenant table, IssuerValue is the value of the issuer claim for the tenant. Azure AD için bu, https://sts.windows.net/<tentantID> ve Kiracı başına benzersiz bir değer verir.For Azure AD, this is https://sts.windows.net/<tentantID> and gives a unique value per tenant.

Ne zaman yeni bir kiracı, Surveys uygulamasını bir kiracı kaydı veritabanına yazar imzalar.When a new tenant signs up, the Surveys application writes a tenant record to the database. İçinde böyle AuthenticationValidated olay.This happens inside the AuthenticationValidated event. (Yapma, önce bu olay, talep değerlerini güvenemez şekilde kimlik belirteci henüz doğrulanması gerekmez çünkü.(Don't do it before this event, because the ID token won't be validated yet, so you can't trust the claim values. Bkz: kimlik doğrulaması.See Authentication.

Surveys uygulamasını ilgili kod şu şekildedir:Here is the relevant code from the Surveys application:

public override async Task TokenValidated(TokenValidatedContext context)
{
    var principal = context.AuthenticationTicket.Principal;
    var userId = principal.GetObjectIdentifierValue();
    var tenantManager = context.HttpContext.RequestServices.GetService<TenantManager>();
    var userManager = context.HttpContext.RequestServices.GetService<UserManager>();
    var issuerValue = principal.GetIssuerValue();
    _logger.AuthenticationValidated(userId, issuerValue);

    // Normalize the claims first.
    NormalizeClaims(principal);
    var tenant = await tenantManager.FindByIssuerValueAsync(issuerValue)
        .ConfigureAwait(false);

    if (context.IsSigningUp())
    {
        if (tenant == null)
        {
            tenant = await SignUpTenantAsync(context, tenantManager)
                .ConfigureAwait(false);
        }

        // In this case, we need to go ahead and set up the user signing us up.
        await CreateOrUpdateUserAsync(context.Ticket, userManager, tenant)
            .ConfigureAwait(false);
    }
    else
    {
        if (tenant == null)
        {
            _logger.UnregisteredUserSignInAttempted(userId, issuerValue);
            throw new SecurityTokenValidationException($"Tenant {issuerValue} is not registered");
        }

        await CreateOrUpdateUserAsync(context.Ticket, userManager, tenant)
            .ConfigureAwait(false);
    }
}

Bu kod şunları yapar:This code does the following:

  1. Kiracının veren değerini zaten veritabanında olup olmadığını denetleyin.Check if the tenant's issuer value is already in the database. Kiracı, açmadı varsa FindByIssuerValueAsync null döndürür.If the tenant has not signed up, FindByIssuerValueAsync returns null.
  2. Kullanıcı Kaydolma varsa:If the user is signing up:
    1. Kiracı veritabanına ekleme (SignUpTenantAsync).Add the tenant to the database (SignUpTenantAsync).
    2. Kimliği doğrulanmış kullanıcı veritabanına ekleme (CreateOrUpdateUserAsync).Add the authenticated user to the database (CreateOrUpdateUserAsync).
  3. Aksi halde normal oturum açma akışını tamamlayın:Otherwise complete the normal sign-in flow:
    1. Kiracının veren veritabanında bulunamadı, Kiracı kayıtlı değil ve müşteri kaydolması anlamına gelir.If the tenant's issuer was not found in the database, it means the tenant is not registered, and the customer needs to sign up. Bu durumda, kimlik doğrulamasının başarısız olmasına neden olacak bir özel durum.In that case, throw an exception to cause the authentication to fail.
    2. Yoksa zaten yoksa, bu kullanıcı için bir veritabanı kaydı oluşturma (CreateOrUpdateUserAsync).Otherwise, create a database record for this user, if there isn't one already (CreateOrUpdateUserAsync).

İşte SignUpTenantAsync yönteminin Kiracı veritabanına ekler.Here is the SignUpTenantAsync method that adds the tenant to the database.

private async Task<Tenant> SignUpTenantAsync(BaseControlContext context, TenantManager tenantManager)
{
    Guard.ArgumentNotNull(context, nameof(context));
    Guard.ArgumentNotNull(tenantManager, nameof(tenantManager));

    var principal = context.Ticket.Principal;
    var issuerValue = principal.GetIssuerValue();
    var tenant = new Tenant
    {
        IssuerValue = issuerValue,
        Created = DateTimeOffset.UtcNow
    };

    try
    {
        await tenantManager.CreateAsync(tenant)
            .ConfigureAwait(false);
    }
    catch(Exception ex)
    {
        _logger.SignUpTenantFailed(principal.GetObjectIdentifierValue(), issuerValue, ex);
        throw;
    }

    return tenant;
}

Surveys uygulamasını tüm kayıt akışta bir özeti aşağıda verilmiştir:Here is a summary of the entire sign-up flow in the Surveys application:

  1. Kullanıcı Kaydol düğmesi.The user clicks the Sign Up button.
  2. AccountController.SignUp Eylem sınama sonucu döndürür.The AccountController.SignUp action returns a challenge result. Kimlik doğrulama durumu "signup" değeri içerir.The authentication state includes "signup" value.
  3. İçinde RedirectToAuthenticationEndpoint olay ekleme admin_consent istemi.In the RedirectToAuthenticationEndpoint event, add the admin_consent prompt.
  4. Openıd Connect ara yazılımı, Azure AD'ye yeniden yönlendirir ve kullanıcı kimliğini doğrular.The OpenID Connect middleware redirects to Azure AD and the user authenticates.
  5. İçinde AuthenticationValidated olay, "signup" durumu arayın.In the AuthenticationValidated event, look for the "signup" state.
  6. Kiracı veritabanına eklenir.Add the tenant to the database.

SonrakiNext