Principales respuestas
Consulta sobre Autenticación Windows + Roles de BDD local

Pregunta
-
Buenas como están?
Quisiera pedirles un favor, si puede orientarme respecto a crear una app.net mvc con autenticación de usuario de dominio AD y que los roles sean administrador por dicha aplicación ya que es una intranet. Utilizo Entity framework y mi modelo de capas es el siguiente:
1)Data (entityFramework): acceso a datos de la aplicación y modelos de otras aplicaciones
2)Services: Negocio
3)ExternalServices: negocio con otras aplicaciones
4)Contracts: definición de los contratos de los servicios anteriores
5)MVC: projecto MVC modelo vista controlador
6)Pruebas unitarias
Estuve investigando en este enlace que está interesante, pero no usa usuarios de dominio AD, sino propio de la aplicación:
https://anexsoft.com/roles-y-permisos-personalizados-con-asp-net-mvc
Respecto a mi modelo es muy parecido al enlace anterior:
Conocen algún hilo para poder seguir en español?
Desde ya se agradece la respuesta.
Saludos
Rodri
Respuestas
-
Hola, entendí mal, muy mal y disculpas por ello. Lo que deseas es poder gestionar los roles de tu aplicativo. No?
Vale, necesitas entonces un RoleProvider
Para ello puedes implementar algo así
public class CustomRoleProvider : RoleProvider { public override string ApplicationName { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public override void AddUsersToRoles(string[] usernames, string[] roleNames) { throw new NotImplementedException(); } public override void CreateRole(string roleName) { throw new NotImplementedException(); } public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) { throw new NotImplementedException(); } public override string[] FindUsersInRole(string roleName, string usernameToMatch) { throw new NotImplementedException(); } public override string[] GetAllRoles() { throw new NotImplementedException(); } public override string[] GetRolesForUser(string username) { using (SampleDBEntities objContext = new SampleDBEntities()) // Tu contexto de EF { var objUser = objContext.Users.FirstOrDefault(x => x.AppUserName == username); if (objUser == null) { return null; } else { return objUser.Roles.Select(x => x.RoleName).ToArray(); } } } public override string[] GetUsersInRole(string roleName) { throw new NotImplementedException(); } public override bool IsUserInRole(string username, string roleName) { var roles = GetRolesForUser(username); return roles.Contains(roleName,StringComparer.OrdinalIgnoreCase); } public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) { throw new NotImplementedException(); } public override bool RoleExists(string roleName) { throw new NotImplementedException(); } }
Como ves implementas las operaciones requeridas de RoleProvider usando tu contexto de EF.
Luego estableces en tu web.config el proveedor
<roleManager cacheRolesInCookie="true" defaultProvider="CustomRoleProvider" enabled="true"> <providers> <clear /> <add name="CustomRoleProvider" type="[Namespace here].CustomRoleProvider, [Application Assembly here]" /> </providers> </roleManager>
También deberías implementar un atributo que herede de AuthorizationAttribute para gestionar los roles y permitir o no el acceso al método.
Supongamos que tendrás los siguientes roles (así evitas las "magic string")
public enum Roles { User, Developer, Administrator }
Implementamos el attribute
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] public class RoleAuthorizeAttribute : AuthorizeAttribute { public RoleAuthorizeAttribute(params object[] roles) { if (roles.Any(r => r.GetType().BaseType != typeof(Enum))) throw new ArgumentException("The roles parameter may only contain enums", "roles"); var temp = roles.Select(r => Enum.GetName(r.GetType(), r)).ToList(); Roles = string.Join(",", temp); } public override void OnAuthorization(AuthorizationContext filterContext) { var request = filterContext.HttpContext.Request; var url = new UrlHelper(filterContext.RequestContext); var accessDeniedUrl = url.Action("AccessDenied", "Error"); if (!string.IsNullOrEmpty(base.Roles)) { var isRoleError = true; var rolesAllowed = base.Roles.Split(','); var user = filterContext.HttpContext.User; if (user != null && rolesAllowed.Any()) { foreach (var role in rolesAllowed) if (user.IsInRole(role)) isRoleError = false; } if (isRoleError) { if (request.IsAjaxRequest()) filterContext.Result = new JsonResult { Data = new { error = true, signinerror = true, message = "Access denied", url = accessDeniedUrl }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; else filterContext.Result = new RedirectResult(accessDeniedUrl); } } } }
Y para usarlo en tu métdo de acción o en tu controlador
[RoleAuthorize(Roles.User, Roles.Developer)] public ActionResult Index() { }
Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos
- Marcado como respuesta Sergio ParraModerator jueves, 14 de enero de 2021 18:49
-
Si, efectivamente esa era otra opción que iba a preguntarte. Para ello deberías desde tu aplicación conectar con el AD y gestionar las cosas empleando System.DirectoryServices, el cual usa un PrincipalContext de una cuenta con permisos de Admin en tu AD. Básicamente en tu RoleProvider en vez de usar tu context de EF usarías las herramientas de DirectoryServices
Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos
- Propuesto como respuesta EricRRModerator martes, 12 de enero de 2021 21:47
- Marcado como respuesta Sergio ParraModerator jueves, 14 de enero de 2021 18:50
-
Enlaces interesantes
http://slalomdev.blogspot.com/2008/08/active-directory-role-provider.html?m=1
https://masudprogrammer.wordpress.com/2012/11/21/active-directory-role-provider-with-asp-net-c/
Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos
- Propuesto como respuesta KHURRAM RAHIM miércoles, 13 de enero de 2021 10:29
- Marcado como respuesta Sergio ParraModerator jueves, 14 de enero de 2021 18:50
Todas las respuestas
-
-
-
-
Hola, entendí mal, muy mal y disculpas por ello. Lo que deseas es poder gestionar los roles de tu aplicativo. No?
Vale, necesitas entonces un RoleProvider
Para ello puedes implementar algo así
public class CustomRoleProvider : RoleProvider { public override string ApplicationName { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public override void AddUsersToRoles(string[] usernames, string[] roleNames) { throw new NotImplementedException(); } public override void CreateRole(string roleName) { throw new NotImplementedException(); } public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) { throw new NotImplementedException(); } public override string[] FindUsersInRole(string roleName, string usernameToMatch) { throw new NotImplementedException(); } public override string[] GetAllRoles() { throw new NotImplementedException(); } public override string[] GetRolesForUser(string username) { using (SampleDBEntities objContext = new SampleDBEntities()) // Tu contexto de EF { var objUser = objContext.Users.FirstOrDefault(x => x.AppUserName == username); if (objUser == null) { return null; } else { return objUser.Roles.Select(x => x.RoleName).ToArray(); } } } public override string[] GetUsersInRole(string roleName) { throw new NotImplementedException(); } public override bool IsUserInRole(string username, string roleName) { var roles = GetRolesForUser(username); return roles.Contains(roleName,StringComparer.OrdinalIgnoreCase); } public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) { throw new NotImplementedException(); } public override bool RoleExists(string roleName) { throw new NotImplementedException(); } }
Como ves implementas las operaciones requeridas de RoleProvider usando tu contexto de EF.
Luego estableces en tu web.config el proveedor
<roleManager cacheRolesInCookie="true" defaultProvider="CustomRoleProvider" enabled="true"> <providers> <clear /> <add name="CustomRoleProvider" type="[Namespace here].CustomRoleProvider, [Application Assembly here]" /> </providers> </roleManager>
También deberías implementar un atributo que herede de AuthorizationAttribute para gestionar los roles y permitir o no el acceso al método.
Supongamos que tendrás los siguientes roles (así evitas las "magic string")
public enum Roles { User, Developer, Administrator }
Implementamos el attribute
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] public class RoleAuthorizeAttribute : AuthorizeAttribute { public RoleAuthorizeAttribute(params object[] roles) { if (roles.Any(r => r.GetType().BaseType != typeof(Enum))) throw new ArgumentException("The roles parameter may only contain enums", "roles"); var temp = roles.Select(r => Enum.GetName(r.GetType(), r)).ToList(); Roles = string.Join(",", temp); } public override void OnAuthorization(AuthorizationContext filterContext) { var request = filterContext.HttpContext.Request; var url = new UrlHelper(filterContext.RequestContext); var accessDeniedUrl = url.Action("AccessDenied", "Error"); if (!string.IsNullOrEmpty(base.Roles)) { var isRoleError = true; var rolesAllowed = base.Roles.Split(','); var user = filterContext.HttpContext.User; if (user != null && rolesAllowed.Any()) { foreach (var role in rolesAllowed) if (user.IsInRole(role)) isRoleError = false; } if (isRoleError) { if (request.IsAjaxRequest()) filterContext.Result = new JsonResult { Data = new { error = true, signinerror = true, message = "Access denied", url = accessDeniedUrl }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; else filterContext.Result = new RedirectResult(accessDeniedUrl); } } } }
Y para usarlo en tu métdo de acción o en tu controlador
[RoleAuthorize(Roles.User, Roles.Developer)] public ActionResult Index() { }
Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos
- Marcado como respuesta Sergio ParraModerator jueves, 14 de enero de 2021 18:49
-
Hola,
Gracias por levantar tu consulta en los foros de MSDN.
Eric Ruiz
____________________________
Por favor recuerde "Marcar como respuesta" las respuestas que hayan resuelto su problema, es una forma común de reconocer a aquellos que han ayudado, y hace que sea más fácil para los otros visitantes encontrar la solución más tarde.
Si tiene algún cumplido o reclamo sobre el soporte de MSDN siéntase en la libertad de contactar MSDNFSF@microsoft.com.
-
-
Hola Sergio, ayer estuvimos analizando tu respuesta y me dejó muy conforme. Esto es en el caso de querer administrar los roles dentro de la aplicación.
En caso de querer manejar los roles a través de un grupo de Active Directory (esto es asignando un usuario del dominio a un grupo de AD, y que la aplicación asigne las funciones correspondientes de acuerdo a ello, posees algo de información para realizar eso?
En este caso minimizaría el diseño de la aplicación web.
Disculpas por las molestias.
Muchas gracias.
Ss.
Rodrigo
-
Si, efectivamente esa era otra opción que iba a preguntarte. Para ello deberías desde tu aplicación conectar con el AD y gestionar las cosas empleando System.DirectoryServices, el cual usa un PrincipalContext de una cuenta con permisos de Admin en tu AD. Básicamente en tu RoleProvider en vez de usar tu context de EF usarías las herramientas de DirectoryServices
Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos
- Propuesto como respuesta EricRRModerator martes, 12 de enero de 2021 21:47
- Marcado como respuesta Sergio ParraModerator jueves, 14 de enero de 2021 18:50
-
Enlaces interesantes
http://slalomdev.blogspot.com/2008/08/active-directory-role-provider.html?m=1
https://masudprogrammer.wordpress.com/2012/11/21/active-directory-role-provider-with-asp-net-c/
Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos
- Propuesto como respuesta KHURRAM RAHIM miércoles, 13 de enero de 2021 10:29
- Marcado como respuesta Sergio ParraModerator jueves, 14 de enero de 2021 18:50
-
-
Ya creamos el grupo de seguridad en AD. Luego asigné mi usuario DOMINIO\USER en el grupo anterior, agregué lo siguiente en el web.config:
<system.web>
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2" />
<authentication mode="Windows" />
<authorization>
<deny users="?" />
</authorization>
<roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider">
<providers>
<clear />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
</system.web>
<runtime>Luego agregué en el HomeController la autorización al controlador Index (Authorize(Roles = @"DOMINIO\GRUPOAD") y anduvo, además probé en el about y contact, también anduvo. Me resultó raro que pida usuario y contraseña en cada link. Le di guardar contraseña y ya no lo pide más, pero creo que no debería hacerlo, ya que el usuario no debe recibirlo.
Authorize(Roles = @"DOMINIO\GRUPOAD"
Ahora debería asignar las autorizaciones a cada controlador? Eso es todo? o me está faltando algo?
SS.
-
Hola, si el atributo lo tienes escrito a nivel de clase (controller) en cada petición a ese controlador, va a chequear la autorización. Colocarlo en los métodos de acción que necesiten ser autenticados es suficiente. Lo de cada link no te entiendo, puedes mostrar algo de código? Esos links dónde apuntan?
Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos
- Editado Sergio ParraModerator miércoles, 13 de enero de 2021 15:20
-