Passo a passo: Autenticação de servidor para servidor multilocatário

 

Publicado: janeiro de 2017

Aplicável a: Dynamics 365 (online)

Este passo a passo descreverá as etapas para a criação de um aplicativo Web multilocatário que pode se conectar a um locatário do Atualização de dezembro de 2016 para Microsoft Dynamics 365 (online) usando o modelo de aplicativo Web MVC do Microsoft Visual Studio 2015.

Requisitos

  • Visual Studio 2015 com ferramentas de desenvolvedor da Web instaladas

  • Um locatário do Atualização de dezembro de 2016 para Microsoft Dynamics 365 (online) associado ao seu locatário do Active Directory do Azure (Azure AD).

  • Um segundo locatário do Atualização de dezembro de 2016 para Microsoft Dynamics 365 (online) associado com um locatário do Azure AD diferente. Este locatário representa um assinante para seu aplicativo. Esta pode ser uma assinatura de avaliação do Atualização de dezembro de 2016 para Microsoft Dynamics 365 (online).

A meta deste passo a passo

Quando você concluir este passo a passo, você criará um aplicativo Web MVC que usará o WhoAmIRequest Class para recuperar dados sobre o usuário que o aplicativo usa para se conectar ao locatário do Dynamics 365 (online).

Quando você executar o aplicativo com êxito, verá um comando Entrar no canto superior direito.

The sign in command in the app

Clique no comando Entrar e você será redirecionado para o Azure AD para suas credenciais.

Depois de entrar, você verá que há um comando WhoAmI.

The WhoAmI command

Clique em WhoAmI e você deverá ver o seguinte:

Results of a WhoAmI request

Quando você consultar seu locatário do Dynamics 365, verá que os resultados retornados da mensagem WhoAmI se referem a uma conta de usuário de aplicativo específica que você configurou para o aplicativo Web usar em vez da conta de usuário usada atualmente.

Verificar o locatário do Azure AD

Antes de começar, conecte-se ao seu Centro de administração do Office 365https://portal.office.com e, na lista suspensa Centros de administração, verifique se você vê o Dynamics 365 e o Azure AD.

Admin Centers with Azure Active Directory and Dynamics 365

Se a sua assinatura do Azure AD não estiver associada a uma assinatura do Dynamics 365, você não poderá conceder privilégios para seu aplicativo acessar dados do Dynamics 365.

Se você não vir esta opção, consulte Registrar sua assinatura gratuita do Azure Active Directory para obter informações sobre como se registrar para obter sua assinatura do Azure AD.

Se você já tiver uma assinatura do Azure mas se ela não estiver associada à sua conta do Microsoft Office 365, consulte Associar sua conta do Office 365 ao Azure AD para criar e gerenciar aplicativos.

Criar um aplicativo Web MVC

Usando o Visual Studio 2015, você pode criar um novo aplicativo Web MVC e registrá-lo em seu locatário do Azure AD.

  1. Abra o Visual Studio 2015.

  2. Verifique se o Conta da Microsoft com o qual você entrou é igual ao acesso ao com acesso ao locatário do Azure AD que você deseja usar para registrar seu aplicativo.

  3. Clique em Novo Projeto e selecione .NET Framework 4.6.1 e o modelo Aplicativo Web ASP.NET.

    Clique em OK e, no diálogo Novo projeto ASP.NET, selecione MVC.

  4. Clique no botão Alterar Autenticação e, no diálogo, selecione Contas Corporativas ou de Estudante.

  5. Na lista suspensa, selecione Nuvem – Várias Organizações.

    ASP.NET MVC Change Authentication Dialog

  6. Clique em OK e conclua a inicialização do projeto.

    Observação

    A criação de um projeto do Visual Studio dessa maneira registrará o aplicativo no seu locatário do Azure AD e adicionará as seguintes chaves ao Web.Config appSettings:

    <add key="ida:ClientId" value="baee6b74-3c39-4c04-bfa5-4414f3dd1c26" />
    <add key="ida:AADInstance" value="https://login.microsoftonline.com/" />
    <add key="ida:ClientSecret" value="HyPjzuRCbIl/7VUJ2+vG/+Gia6t1+5y4dvtKAcyztL4=" /> 
    

Registrar seu aplicativo no Azure AD

Se você tiver seguido as etapas em Criar um aplicativo Web MVC, deverá descobrir que o projeto de aplicativo Web criado no Visual Studio já está registrado em seus aplicativos do Azure AD. Mas há mais uma etapa que você deve executar no portal do Azure AD.

  1. Vá para https://portal.azure.com e selecione Azure Active Directory.

  2. Clique em Registros de aplicativo e procure pelo aplicativo que você criou usando o Visual Studio. Na área Geral, verifique as propriedades:

    Application registration data in Azure Active Directory

  3. Verifique se a propriedade ID do Aplicativo corresponde ao valor de ClientId adicionado às suas Web.Config appSettings.

  4. O valor de URL da Home Page deve corresponder à propriedade SSL URL em seu projeto do Visual Studio e deve direcionar para uma URL de localhost, isto é, https://localhost:44392/.

    Observação

    Você precisará alterar isso mais tarde quando realmente publicar seu aplicativo. Mas você precisa ter isso definido para o valor de localhost correto para depuração.

  5. Você precisa atribuir ao aplicativo os privilégios para acessar dados do Dynamics 365. Na área Acesso à API clique em Permissões necessárias. Você deverá ver que ele já tem as permissões para o Windows Active Directory do Azure.

  6. Clique em Adicionar, então em Selecionar uma API. Na lista, selecione Dynamics 365 e clique no botão Selecionar.

  7. Em Selecionar permissões, selecione Acessar o Dynamics 365 como usuários da organização. Em seguida, clique no botão Selecionar.

  8. Clique Concluído para adicionar essas permissões. Quando terminar, você deverá ver as permissões aplicadas:

    Dynamics 365 permissions applied to application in Azure Active Directory

  9. Na área Acesso da API , confirme que um valor Chave foi adicionado. O valor Chave não fica visível no portal do Azure após a criação do aplicativo, mas esse valor foi adicionado às suas Web.Config appSettings como ClientSecret.

Criar um usuário de aplicativo

Usando as etapas de a77637f4-420a-4686-9084-d0288d9154af#bkmk_ManuallyCreateUser, crie um usuário de aplicativo com o valor de Id do Aplicativo do seu registro de aplicativo, que também é igual ao valor de ClientId em Web.Config.

Adicionar Assemblies

Adicionar os seguintes pacotes NuGet ao seu projeto

Pacote

Versão

Microsoft.CrmSdk.CoreAssemblies

Última versão

Microsoft.IdentityModel.Clients.ActiveDirectory

2.22.302111727

Microsoft.IdentityModel.Tokens

5.0.0

Microsoft.Azure.ActiveDirectory.GraphClient

2.1.0

Observação

Não atualize os assemblies Microsoft.IdentityModel.Clients.ActiveDirectory para a versão mais recente. A versão 3.x desses assemblies alterou uma interface da qual Microsoft.CrmSdk.CoreAssemblies depende.

Para obter informações sobre o gerenciamento de pacotes NuGet , consulte Documentação do NuGet: Gerenciando pacotes NuGet usando a interface do usuário

Aplicar alterações de código ao modelo MVC

As alterações feitas no código a seguir fornecerão funcionalidade básica para usar a mensagem Dynamics 365WhoAmI e verificar se a identidade de conta do usuário de aplicativo está sendo usada pelo aplicativo.

Web.config

Adicione as seguintes chaves às appSettings.

<add key="ida:OrganizationHostName" value="https://{0}.crm.dynamics.com" /> 

A cadeia de caracteres ida:OrganizationHostName terá o nome da organização do Dynamics 365 online do assinante adicionado ao espaço reservado para que o serviço correto seja acessado.

<add key="owin:appStartup" value="<your app namespace>.Startup" />

A cadeia de caracteres owin:appStartup garante que o middleware OWIN use a classe Startup neste projeto. Caso contrário , você obterá o seguinte erro:

- No assembly found containing an OwinStartupAttribute.
- No assembly found containing a Startup or [AssemblyName].Startup class.

Mais informações: ASP.NET: Detecção de classe de inicialização OWIN

Controllers/HomeController.cs

Adicione o decorador AllowAnonymous à ação Index. Isso permite o acesso a página padrão sem autenticação.

using System.Web.Mvc;

namespace SampleApp.Controllers
{
    [Authorize]
    public class HomeController : Controller
    {
        [AllowAnonymous]
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}

Observação

Em seu aplicativo ou serviço Web, não se espera que você permita o acesso anônimo. Aqui, o acesso anônimo é usado para simplicidade. O controle de acesso ao seu aplicativo está fora do escopo deste passo a passo.

Views/Shared/_Layout.cshtml

Para exibir o link do comando WhoAmI para usuários autenticados, você precisará editar este arquivo.

Localize o elemento div com a classe navbar-collapse collapse e edite-o para incluir o código abaixo:

<div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
     <li>@Html.ActionLink("Home", "Index", "Home")</li>
     <li>@Html.ActionLink("About", "About", "Home")</li>
     <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
     @if (Request.IsAuthenticated)
     {
         <li>@Html.ActionLink("WhoAmI", "Index", "CrmSdk")</li>
     }
    </ul>

    @Html.Partial("_LoginPartial")
   </div>

App_Start/Startup.Auth.cs

As alterações a seguir invocarão a estrutura de consentimento quando um novo locatário fizer logon no aplicativo:

public partial class Startup
 {
  private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
  private string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
  //Not used   
  //private string graphResourceID = "https://graph.windows.net";    
  private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
  private string authority = aadInstance + "common";
  private ApplicationDbContext db = new ApplicationDbContext();

  //Added
  private string OrganizationHostName = ConfigurationManager.AppSettings["ida:OrganizationHostName"];

  public void ConfigureAuth(IAppBuilder app)
  {

   app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

   app.UseCookieAuthentication(new CookieAuthenticationOptions { });

   app.UseOpenIdConnectAuthentication(
       new OpenIdConnectAuthenticationOptions
       {
        ClientId = clientId,
        Authority = authority,
        TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
        {
         /*
         instead of using the default validation 
         (validating against a single issuer value, as we do in line of business apps), 
         we inject our own multitenant validation logic
         */
         ValidateIssuer = false,
        },
        Notifications = new OpenIdConnectAuthenticationNotifications()
        {
         SecurityTokenValidated = (context) =>
                  {
                   return Task.FromResult(0);
                  },
         AuthorizationCodeReceived = (context) =>
                  {
                   var code = context.Code;

                   ClientCredential credential = new ClientCredential(clientId, appKey);
                   string tenantID = context
                    .AuthenticationTicket
                    .Identity
                    .FindFirst("https://schemas.microsoft.com/identity/claims/tenantid")
                    .Value;

                   /* Not used
                  string signedInUserID = context
                     .AuthenticationTicket
                     .Identity
                     .FindFirst(ClaimTypes.NameIdentifier)
                     .Value;  
                     */

                   //Added
                   var resource = string.Format(OrganizationHostName, '*');
                   //Added
                   Uri returnUri = new Uri(
                    HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)
                    );

                   /* Changed below
                    AuthenticationContext authContext = 
                    new AuthenticationContext(
                     aadInstance + tenantID, 
                     new ADALTokenCache(signedInUserID)
                     );
                    */
                   //Changed version
                   AuthenticationContext authContext =
                   new AuthenticationContext(aadInstance + tenantID);

                   /* Changed below
                   AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
                       code, 
                       new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), 
                       credential, 
                       graphResourceID);
                   */
                   //Changed version
                   AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
                       code,
                       new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)),
                       credential,
                       resource);

                   return Task.FromResult(0);
                  },
         AuthenticationFailed = (context) =>
                  {
                   context.OwinContext.Response.Redirect("/Home/Error");
                   context.HandleResponse(); // Suppress the exception
                   return Task.FromResult(0);
                  }
        }
       });

  }
 }

Add Controllers/CrmSdkController

Adicione o seguinte CrmSdkController.cs à pasta Controllers. Este código executará a mensagem WhoAmI

  1. Clique com o botão direito do mouse na pasta Controllers e selecione Adicionar > Controlador…

  2. No diálogo Adicionar Scaffold, selecione Controlador MVC5 – Vazio

  3. Clique em Adicionar

  4. Cole o seguinte código que substitui <Your app namespace> pelo namespace do seu aplicativo.

using Microsoft.IdentityModel.Clients.ActiveDirectory; 
using Microsoft.Xrm.Sdk; 
using Microsoft.Xrm.Sdk.WebServiceClient; 
using System; using System.Configuration; 
using System.Linq; 
using System.Security.Claims; 
using System.Web.Mvc;

namespace <Your app namespace>
{
 [Authorize]
 public class CrmSdkController : Controller
    {

  private string clientId = 
   ConfigurationManager.AppSettings["ida:ClientId"];
  private string authority = 
   ConfigurationManager.AppSettings["ida:AADInstance"] + "common";
  private string aadInstance = 
   ConfigurationManager.AppSettings["ida:AADInstance"];
  private string OrganizationHostName = 
   ConfigurationManager.AppSettings["ida:OrganizationHostName"];
  private string appKey = 
   ConfigurationManager.AppSettings["ida:ClientSecret"];


  // GET: CrmSdk
  public ActionResult Index()
  {
   string tenantID = ClaimsPrincipal
    .Current
    .FindFirst("https://schemas.microsoft.com/identity/claims/tenantid")
    .Value;
   // Clean organization name from user logged
   string organizationName = User.Identity.Name.Substring(
    User.Identity.Name.IndexOf('@') + 1, 
    User.Identity.Name.IndexOf('.') - (User.Identity.Name.IndexOf('@') + 1)
    );
   //string crmResourceId = "https://[orgname].crm.microsoftonline.com";
   var resource = string.Format(OrganizationHostName, organizationName);
   // Request a token using application credentials
   ClientCredential clientcred = new ClientCredential(clientId, appKey);
   AuthenticationContext authenticationContext = 
    new AuthenticationContext(aadInstance + tenantID);
   AuthenticationResult authenticationResult = 
    authenticationContext.AcquireToken(resource, clientcred);
   var requestedToken = authenticationResult.AccessToken;
   // Invoke SDK using using the requested token
   using (var sdkService =
    new OrganizationWebProxyClient(
     GetServiceUrl(organizationName), false)
     )
   {
    sdkService.HeaderToken = requestedToken;
    OrganizationRequest request = new OrganizationRequest() {
     RequestName = "WhoAmI"
    };
    OrganizationResponse response = sdkService.Execute(request);
    return View((object)string.Join(",", response.Results.ToList()));
   }
  }

  private Uri GetServiceUrl(string organizationName)
  {
   var organizationUrl = new Uri(
    string.Format(OrganizationHostName, organizationName)
    );
   return new Uri(
    organizationUrl + 
    @"/xrmservices/2011/organization.svc/web?SdkClientVersion=8.2"
);
  }
 }
}

Views/CrmSdk

Adicione um novo modo de exibição chamado Index.

  1. Clique com o botão direito do mouse na pasta CrmSdk e selecione Adicionar > Exibir…

  2. No diálogo Adicionar Modo de Exibição, defina os seguintes valores:

    MVC Add View Dialog

  3. Clique em Adicionar

  4. Substitua o código gerado pelo seguinte:

    @model string
    @{
     ViewBag.Title = "SDK Connect";
    }
    
    
    <h2>@ViewBag.Title.</h2>
    
    <p>Connected and executed sdk command WhoAmI.</p>
    
    <p>Value: @Model</p>
    

Depurar o aplicativo

Quando você pressionar F5 para depurar o aplicativo, poderá obter o erro de que o certificado que está acessando localhost usando SSL não é confiável. A seguir, alguns links para resolver esse problema com o Visual Studio e o IIS Express:

Observação

Para esta etapa, é possível usar apenas o Conta da Microsoft associado ao locatário do Azure AD e o locatário do Dynamics 365 ao qual ele está associado. Na verdade, isso não está demonstrando um cenário multilocatário. Nós faremos isso na próxima etapa. Esta etapa destina-se somente a verificar se o código funciona antes da introdução da complexidade adicional de testes da funcionalidade multilocatário real.

Consulte as etapas descritas emA meta deste passo a passo para testar o aplicativo.

Neste ponto, você pode verificar se a conta de usuário do aplicativo foi usada. Uma maneira fácil é verificar isso usando a API Web do Dynamics 365. Digite a URL a seguir em uma guia ou janela separada, substituindo o valor de UserId do aplicativo.

[Organization URI]/api/data/v8.2/systemusers(<UserId value>)?$select=fullname

A resposta do JSON deve ser parecida com a seguinte. Observe que o valor de fullname será o usuário do aplicativo criado na etapa Criar um usuário de aplicativo, em vez do usuário do Dynamics 365 utilizado para entrar no aplicativo.

    {
        "@odata.context": "[Organization Uri]/api/data/v8.2/$metadata#systemusers(fullname)/$entity",
        "@odata.etag": "W/\"603849\"",
        "fullname": "S2S User",
        "systemuserid": "31914b34-be8d-e611-80d8-00155d892ddc",
        "ownerid": "31914b34-be8d-e611-80d8-00155d892ddc"
    }

Configurar assinante de teste

Agora que você já verificou se o aplicativo funciona, é hora de testar a conectividade para um locatário diferente do Dynamics 365 (online). Usando uma organização diferente do Dynamics 365 (online), será necessário executar as etapas a seguir.

Dar consentimento do locatário que está assinando

Para consentir, execute as etapas a seguir enquanto estiver conectado como o administrador do Azure AD:

  1. Enquanto estiver depurando seu aplicativo, abra uma janela InPrivate ou Incognito separada.

  2. No campo de endereço da janela, digite a URL do seu aplicativo, isto é, https://localhost:44392/

  3. Clique no botão Entrar e será solicitado que você dê consentimento.

    Azure Active Directory consent form

Depois de dar consentimento, você voltará para o aplicativo, mas ainda não poderá usá-lo. Se você clicar em WhoAmI nesse ponto, espere a seguinte exceção:

System.ServiceModel.Security.MessageSecurityException
HResult=-2146233087
  Message=The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Bearer authorization_uri=https://login.windows.net/4baaeaaf-2771-4583-99eb-7c7e39aa1e74/oauth2/authorize, resource_id=https://<org name>.crm.dynamics.com/'.
InnerException.Message =The remote server returned an error: (401) Unauthorized.

Ao dar consentimento, o aplicativo do seu locatário do Azure AD será adicionado aos aplicativos no locatário do active directory do assinante.

Criar um direito de acesso personalizado no locatário do assinante

O usuário do aplicativo que você precisará criar deverá estar associado a um direito de acesso personalizado que defina seus privilégios. Para esta etapa de testes manuais, primeiro crie manualmente um direito de acesso personalizado.Para obter mais informações:TechNet: Criar ou editar um direito de acesso

Observação

O usuário do aplicativo não pode estar associado a um dos direitos de acesso padrão do Dynamics 365. Você deve criar um direito de acesso personalizado a ser associado ao usuário do aplicativo.

Criar o usuário do aplicativo do assinante

Para os fins deste passo a passo, criaremos manualmente o usuário do aplicativo para verificar a conectividade de um locatário diferente. Quando você implantar em assinantes reais, vai querer automatizar isso.Para obter mais informações:a77637f4-420a-4686-9084-d0288d9154af#bkmk_PrepareMethodToDeployAppUser

Você cria o usuário do aplicativo manualmente usando os mesmos valores usados para sua organização de desenvolvimento em Criar um usuário de aplicativo. A exceção é que você deve ter concluído a etapa para dar consentimento primeiro. Quando você salvar o usuário, os valores de URI da ID do Aplicativo e ID do Objeto do Azure AD serão definidos. Você não poderá salvar o usuário se não tiver dado o consentimento primeiro.

Por fim, associe o usuário do aplicativo ao direito de acesso personalizado adicionado na etapa anterior.

Testar a conexão do assinante

Repita as etapas de Depurar o aplicativo, exceto o uso das credenciais para um usuário do outro locatário do Dynamics 365.

Confira Também

Usar a autenticação multilocatário de servidor a servidor
Usar a autenticação de locatário único de servidor a servidor
Criar aplicativos da web usando a autenticação S2S (servidor para servidor)
Conectar a Microsoft Dynamics 365

Microsoft Dynamics 365

© 2017 Microsoft. Todos os direitos reservados. Direitos autorais