Tutorial: Autenticación multiempresa entre servidores
Publicado: enero de 2017
Se aplica a: Dynamics 365 (online)
En este tutorial se describirán los pasos para crear una aplicación web multiempresa que se pueda conectar a un inquilino de Actualización de diciembre de 2016 para Microsoft Dynamics 365 (online) mediante la plantilla de la aplicación web MVC de Microsoft Visual Studio 2015.
Requisitos
Visual Studio 2015 con herramientas de desarrollo web instaladas
Un inquilino de Actualización de diciembre de 2016 para Microsoft Dynamics 365 (online) asociado al inquilino de Azure Active Directory (Azure AD).
Un segundo inquilino de Actualización de diciembre de 2016 para Microsoft Dynamics 365 (online) asociado a otro inquilino de Azure AD. Este inquilino representa un suscriptor de la aplicación. Puede ser una suscripción de prueba a Actualización de diciembre de 2016 para Microsoft Dynamics 365 (online).
Objetivo de este tutorial
Al completar este tutorial tendrá una aplicación web MVC que usará la WhoAmIRequest Class para recuperar datos sobre el usuario que la aplicación usa para conectarse al inquilino de Dynamics 365 (online).
Al ejecutar la aplicación correctamente verá un comando Iniciar sesión en la esquina superior derecha.
Haga clic en el comando Iniciar sesión y pasará a Azure AD para sus credenciales.
Una vez que haya iniciado sesión, verá que hay un comando WhoAmI.
Haga clic en WhoAmI, y verá lo siguiente:
Cuando busca el inquilino de Dynamics 365 verá que los resultados devueltos del mensaje de WhoAmI hacen referencia a una cuenta de usuario de la aplicación específica que ha configurado para que la use la aplicación web en lugar de la cuenta de usuario que usa actualmente.
Comprobar el inquilino de Azure AD
Antes de comenzar, conéctese al Centro de administración de Office 365https://portal.office.com y en el desplegable Centros de administración, compruebe que ve Dynamics 365 y Azure AD.
Si su suscripción de Azure AD no está asociada a una suscripción de Dynamics 365, no podrá conceder privilegios para que su aplicación acceda a los datos de Dynamics 365.
Si no ve esta opción, vea Registre su suscripción gratuita a Azure Active Directory para obtener información sobre cómo registrarse para obtener su suscripción de Azure AD.
Si ya tiene una suscripción de Azure pero no está asociada a su cuenta de Microsoft Office 365, vea Asociar su cuenta de Office 365 con Azure AD para crear y administrar aplicaciones.
Crear una aplicación web MCV
Con Visual Studio 2015, puede crear una nueva aplicación web MVC y registrarla con el inquilino de Azure AD.
Abra Visual Studio 2015.
Asegúrese de que Cuenta de Microsoft en el que ha iniciado sesión es el mismo con acceso al inquilino de Azure AD que desea usar para registrar su aplicación.
Haga clic en Nuevo proyecto y seleccione .NET Framework 4.6.1 y la plantilla Aplicación web de ASP.NET.
Haga clic en Aceptar, y en el diálogo Nuevo proyecto de ASP.NET seleccione MVC.
Haga clic en el botón Cambiar autenticación y, en el cuadro de diálogo seleccione Cuentas de trabajo y centro educativo.
En la lista desplegable, seleccione Nube – Varias organizaciones.
Haga clic en Aceptar y complete la inicialización del proyecto.
Nota
Al crear un proyecto de Visual Studio de esta manera se registrará la aplicación con el inquilino de Azure AD y se agregarán las siguientes claves a 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=" />
Registre su aplicación en Azure AD
Si ha realizado los pasos en Crear una aplicación web MCV, debe ver que el proyecto de aplicación web que creó en Visual Studio está registrado ya en sus aplicaciones de Azure AD. Pero si hay un paso más que debe realizar en el portal de Azure AD.
Vaya a https://portal.azure.com y seleccione Azure Active Directory.
Haga clic en Registros de la aplicación y busque la aplicación que ha creado mediante Visual Studio. En el área General, compruebe las propiedades:
Compruebe que coincida la propiedad Identificador de aplicación con el valor de ClientId añadido en su Web.Config appSettings.
El valor de Dirección URL de la página principal debe coincidir con la propiedad SSL URL en el proyecto de Visual Studio y debe dirigir a una dirección URL localhost, es decir https://localhost:44392/.
Nota
Necesitará cambiar esto posteriormente cuando publique realmente la aplicación. Pero debe configurar esto con el valor localhost correcto para depuración.
Debe proporcionar los privilegios de la aplicación para tener acceso a los datos de Dynamics 365. En el área Acceso de API haga clic en Permisos requeridos. Debe ver que ya tiene permisos para Windows Azure Active Directory.
Haga clic en Agregar y, a continuación, en Seleccionar una API. En la lista, seleccione Dynamics 365 y luego haga clic en el botón Seleccionar.
En Seleccionar permisos, seleccione Acceso a Dynamics 365 como usuarios de la organización. A continuación, haga clic en el botón Seleccionar.
Haga clic en Hecho para agregar estos permisos. Cuando finalice deberá ver los permisos aplicados:
En el área Acceso de API, confirme que se haya agregado un valor Clave. El valor Clave no está visible en el portal de Azure vez que se haya creado la aplicación, pero este valor se agregó a la Web.Config appSettings como ClientSecret.
Crear un usuario de la aplicación
Siguiendo los pasos de Cree manualmente un usuario de la aplicación de Dynamics 365, cree un usuario de la aplicación con el valor Id. de la aplicación del registro de la aplicación que también es el mismo que el valor de ClientId en la Web.Config.
Agregar ensamblados
Agregue los siguientes paquetes de NuGet a su proyecto
Paquete |
Versión |
---|---|
Microsoft.CrmSdk.CoreAssemblies |
Versión más reciente |
Microsoft.IdentityModel.Clients.ActiveDirectory |
2.22.302111727 |
Microsoft.IdentityModel.Tokens |
5.0.0 |
Microsoft.Azure.ActiveDirectory.GraphClient |
2.1.0 |
Nota
No actualice los ensamblados de Microsoft.IdentityModel.Clients.ActiveDirectory a la versión más reciente. La versión 3.x de estos ensamblados cambió una interfaz de la que depende Microsoft.CrmSdk.CoreAssemblies.
Para obtener información sobre la administración de paquetes de NuGet, consulte Documentación de NuGet: Administrar paquetes de NuGet mediante la interfaz de usuario
Aplicar cambios de código a la plantilla MVC
Los siguientes cambios de código proporcionarán funcionalidad básica para usar el mensaje de Dynamics 365WhoAmI y comprobar que la identidad de la cuenta de usuario de la aplicación está siendo usada por la aplicación.
Web.config
Agregue las siguientes claves a la appSettings.
<add key="ida:OrganizationHostName" value="https://{0}.crm.dynamics.com" />
La cadena ida:OrganizationHostName tendrá el nombre de la organización en línea de Dynamics 365 del suscriptor agregado en el marcador para que se acceda al servicio correcto.
<add key="owin:appStartup" value="<your app namespace>.Startup" />
La cadena owin:appStartup garantiza que el software intermedio OWIN use la clase Startup en este proyecto. En caso contrario se mostrará el error siguiente:
- No assembly found containing an OwinStartupAttribute.
- No assembly found containing a Startup or [AssemblyName].Startup class.
Más información: ASP.NET: Detección de clase de inicio OWIN
Controllers/HomeController.cs
Agregue el decorador AllowAnonymous a la acción Index. Esto permite el acceso a la página predeterminada sin autenticación.
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();
}
}
}
Nota
En la aplicación web o servicio, no se espera que permita acceso anónimo. El acceso anónimo se usa aquí para simplificar. El control del acceso a la aplicación se encuentra fuera del ámbito de este tutorial.
Views/Shared/_Layout.cshtml
Para mostrar el vínculo de comando WhoAmI para usuarios autenticados, deberá editar este archivo.
Sitúe el elemento div con la clase navbar-collapse collapse y edítelo para incluir el código siguiente:
<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
Los siguientes cambios invocarán el marco de trabajo de consentimiento cuando un nuevo inquilino inicie sesión en la aplicación:
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);
}
}
});
}
}
Agregue Controllers/CrmSdkController
Agregue el siguiente CrmSdkController.cs a la carpeta Controllers. Este código ejecutará el mensaje WhoAmI
Haga clic con el botón secundario en la carpeta Controllers y seleccione Agregar > Controlador…
En el diálogo Agregar andamio, seleccione Controlador MVC5 – Vacío
Haga clic en Agregar
Pegue el siguiente código en sustitución de <Your app namespace> con el espacio de nombres de su aplicación.
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
Agregue una nueva vista con el nombre Index.
Haga clic con el botón secundario en la carpeta CrmSdk y seleccione Agregar > Ver…
En el diálogo Agregar vista, establezca los siguientes valores:
Haga clic en Agregar
Reemplace el código generado con el siguiente:
@model string @{ ViewBag.Title = "SDK Connect"; } <h2>@ViewBag.Title.</h2> <p>Connected and executed sdk command WhoAmI.</p> <p>Value: @Model</p>
Depure la aplicación
Cuando presione F5 para depurar la aplicación puede obtener el error de que no se confía en el certificado que está accediendo a localhost mediante SSL. A continuación hay algunos vínculos para resolver este problema con Visual Studio e IIS Express:
Nota
Para este paso, puede usar simplemente el Cuenta de Microsoft asociado con el inquilino de Azure AD y el inquilino de Dynamics 365 con el que esté asociado. Esto demuestra realmente un escenario multiempresa. Lo haremos en el paso siguiente. Este paso sólo es para comprobar que el código funciona antes de introducir la complejidad adicional de comprobar la funcionalidad real multiempresa.
Consulte los pasos descritos en Objetivo de este tutorial para probar la aplicación.
En este punto puede comprobar que se usó la cuenta de usuario de la aplicación. Una forma simple de comprobarlo es usar la API web de Dynamics 365. Escriba la dirección URL siguiente en una pestaña o ventana separada, sustituyendo el valor de UserId de la aplicación.
[Organization URI]/api/data/v8.2/systemusers(<UserId value>)?$select=fullname
La respuesta de JSON deberá tener el siguiente aspecto. Tenga en cuenta que el valor de fullname será el del usuario de la aplicación que creó en el paso Crear un usuario de la aplicación, en lugar del usuario de Dynamics 365 que usó para iniciar sesión en la aplicación.
{
"@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 suscriptor de prueba
Ahora que ha comprobado que funciona la aplicación, es hora de probar la conectividad con otro inquilino de Dynamics 365 (online). Utilizando otra organización de Dynamics 365 (online) deberá ejecutar los pasos siguientes.
Dar consentimiento desde el inquilino de suscripción
Para dar consentimiento, lleve a cabo los pasos siguientes mientras inicia sesión como administrador de Azure AD:
Cuando está la depuración su aplicación, abra una ventana aparte de InPrivate o de incógnito.
En el campo de dirección del tipo de ventana escriba la dirección URL de la aplicación, es decir https://localhost:44392/
Haga clic en el botón Iniciar sesión y se le pedirá que conceda consentimiento.
Tras conceder consentimiento volverá a la aplicación, pero aún no podrá usarla. Si hace clic en WhoAmI en este punto puede esperar la excepción siguiente:
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.
Concediendo consentimiento, la aplicación del inquilino de Azure AD se agregará a las aplicaciones en el inquilino del directorio activo del suscriptor.
Crear un rol de seguridad personalizado en el inquilino del suscriptor
El usuario de la aplicación que deberá crear debe estar asociado a un rol de seguridad personalizado que defina sus privilegios. Para este paso de prueba manual, primero debe crear manualmente un rol de seguridad personalizado.Más información:TechNet: Creación o edición de roles de seguridad
Nota
El usuario de la aplicación no puede estar asociado con uno de los roles de seguridad de Dynamics 365 predeterminados. Debe crear un rol de seguridad personalizado para asociar con el usuario de la aplicación.
Crear el usuario de la aplicación del suscriptor
Con el objetivo de este tutorial, crearemos manualmente el usuario de la aplicación para comprobar la conectividad desde otro inquilino. Al implementar para suscriptores reales, le convendrá automatizar esto.Más información:Preparar un método para implementar el usuario de la aplicación
Puede crear el usuario de la aplicación manualmente usando los mismos valores que usó para la organización de desarrollo en Crear un usuario de la aplicación. La excepción es que debe haber completado el paso para conceder consentimiento primero. Cuando guarda el usuario, se establecerán los valores de URI de Id. de aplicación y Id. de objeto de Azure AD. No podrá guardar el usuario si no ha concedido consentimiento primero.
Por último, asocie el usuario de la aplicación con el rol de seguridad personalizado que agregó en el paso anterior.
Pruebe la conexión del suscriptor
Repita los pasos descritos en Depure la aplicación, pero use las credenciales para un usuario del otro inquilino de Dynamics 365.
Ver también
Usar autenticación multiempresa entre servidores
Usar autenticación entre servidores de una sola empresa
Crear aplicaciones web mediante autenticación de servidor a servidor (S2S)
Conectarse a Microsoft Dynamics 365
Microsoft Dynamics 365
© 2017 Microsoft. Todos los derechos reservados. Copyright