¿Cómo creo una membresía personalizada para ASP.NET MVC 2 basada en el proveedor de membresía de ASP.NET?¿Cómo creo un proveedor de membresía personalizado para ASP.NET MVC 2?
Respuesta
He creado un nuevo proyecto que contiene un proveedor de suscripciones personalizado y pasó por encima de la ValidateUser
método de la clase abstracta MembershipProvider
:
public class MyMembershipProvider : MembershipProvider
{
public override bool ValidateUser(string username, string password)
{
// this is where you should validate your user credentials against your database.
// I've made an extra class so i can send more parameters
// (in this case it's the CurrentTerritoryID parameter which I used as
// one of the MyMembershipProvider class properties).
var oUserProvider = new MyUserProvider();
return oUserProvider.ValidateUser(username,password,CurrentTerritoryID);
}
}
Entonces conecté ese proveedor a mi proyecto ASP.NET MVC 2 mediante la adición de una referencia y apuntando hacia fuera de mi web.config:
<membership defaultProvider="MyMembershipProvider">
<providers>
<clear />
<add name="MyMembershipProvider"
applicationName="MyApp"
Description="My Membership Provider"
passwordFormat="Clear"
connectionStringName="MyMembershipConnection"
type="MyApp.MyMembershipProvider" />
</providers>
</membership>
que necesito para crear una clase personalizada que hereda la clase abstracta RoleProvider
y anula la GetRolesForUser
cumplido capacho. La Autorización de ASP.NET MVC utiliza ese método para averiguar qué roles se asignan al usuario que ha iniciado sesión actualmente y se asegura de que el usuario tenga permiso para acceder a la acción del controlador.
Estos son los pasos que debemos tomar:
1) Crear una clase personalizada que hereda la clase abstracta RoleProvider y reemplaza el método GetRolesForUser:
public override string[] GetRolesForUser(string username)
{
SpHelper db = new SpHelper();
DataTable roleNames = null;
try
{
// get roles for this user from DB...
roleNames = db.ExecuteDataset(ConnectionManager.ConStr,
"sp_GetUserRoles",
new MySqlParameter("_userName", username)).Tables[0];
}
catch (Exception ex)
{
throw ex;
}
string[] roles = new string[roleNames.Rows.Count];
int counter = 0;
foreach (DataRow row in roleNames.Rows)
{
roles[counter] = row["Role_Name"].ToString();
counter++;
}
return roles;
}
2) Conectar el proveedor de funciones con el ASP.NET MVC 2 aplicación a través de nuestro web.config:
<system.web>
...
<roleManager enabled="true" defaultProvider="MyRoleProvider">
<providers>
<clear />
<add name="MyRoleProvider"
applicationName="MyApp"
type="MyApp.MyRoleProvider"
connectionStringName="MyMembershipConnection" />
</providers>
</roleManager>
...
</system.web>
3) Establecer la autorice (Roles = "xxx, yyy") por encima de la deseada controlador/Acción:
[Authorization(Roles = "Customer Manager,Content Editor")]
public class MyController : Controller
{
......
}
Eso es todo! ¡Ahora funciona!
4) Opcional: establecer una costumbre Authorize
atributo para que podamos redirigir un papel no deseado a una AccessDenied Página:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class MyAuthorizationAttribute : AuthorizeAttribute
{
/// <summary>
/// The name of the master page or view to use when rendering the view on authorization failure. Default
/// is null, indicating to use the master page of the specified view.
/// </summary>
public virtual string MasterName { get; set; }
/// <summary>
/// The name of the view to render on authorization failure. Default is "Error".
/// </summary>
public virtual string ViewName { get; set; }
public MyAuthorizationAttribute()
: base()
{
this.ViewName = "Error";
}
protected void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
{
validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (AuthorizeCore(filterContext.HttpContext))
{
SetCachePolicy(filterContext);
}
else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
}
else if (filterContext.HttpContext.User.IsInRole("SuperUser"))
{
// is authenticated and is in the SuperUser role
SetCachePolicy(filterContext);
}
else
{
ViewDataDictionary viewData = new ViewDataDictionary();
viewData.Add("Message", "You do not have sufficient privileges for this operation.");
filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData };
}
}
protected void SetCachePolicy(AuthorizationContext filterContext)
{
// ** IMPORTANT **
// Since we're performing authorization at the action level, the authorization code runs
// after the output caching module. In the worst case this could allow an authorized user
// to cause the page to be cached, then an unauthorized user would later be served the
// cached page. We work around this by telling proxies not to cache the sensitive page,
// then we hook our custom authorization code into the caching mechanism so that we have
// the final say on whether a page should be served from the cache.
HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
cachePolicy.SetProxyMaxAge(new TimeSpan(0));
cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
}
}
Ahora podemos utilizar nuestro propio atributo hecho para redirigir nuestros usuarios acceder a la vista negado:
[MyAuthorization(Roles = "Portal Manager,Content Editor", ViewName = "AccessDenied")]
public class DropboxController : Controller
{
.......
}
Eso es todo! Super duper!
Éstos son algunos de los enlaces que he usado para obtener toda esta información:
personalizada proveedor de funciones: http://davidhayden.com/blog/dave/archive/2007/10/17/CreateCustomRoleProviderASPNETRolePermissionsSecurity.aspx
Espero que esta información ayuda!
Esto funcionó para mí http://mattwrock.com/post/2009/10/14/Implementing-custom-Membership-Provider-and-Role-Provider-for-Authinticating-ASPNET-MVC-Applications.aspx
gracias, voy a tratar de esto, parece que esto es lo que necesito. –
Buen ejemplo :) – bot
¿Puede resumir los puntos principales del enlace que responden a la pregunta del usuario y proporcionan el enlace? –
he utilizado el código fuente del proveedor de NauckIt.PostgreSQL como base, y modificar para que se adapte a mis necesidades.
También es posible utilizar esto con una cantidad mucho menor de código, no estoy del todo seguro de si este método es tan seguro, pero funciona muy bien con cualquier base de datos que utilice.
en el mundo.asax
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id =
(FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
// Get the stored user-data, in this case, our roles
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
}
lo que esto hace es que lee los papeles de la authCookie que estaba hecho de FormsAuthenticationTicket
y la lógica de inicio de sesión tiene este aspecto
public class dbService
{
private databaseDataContext db = new databaseDataContext();
public IQueryable<vwPostsInfo> AllPostsAndDetails()
{
return db.vwPostsInfos;
}
public IQueryable<role> GetUserRoles(int userID)
{
return (from r in db.roles
join ur in db.UsersRoles on r.rolesID equals ur.rolesID
where ur.userID == userID
select r);
}
public IEnumerable<user> GetUserId(string userName)
{
return db.users.Where(u => u.username.ToLower() == userName.ToLower());
}
public bool logOn(string username, string password)
{
try
{
var userID = GetUserId(username);
var rolesIQueryable = GetUserRoles(Convert.ToInt32(userID.Select(x => x.userID).Single()));
string roles = "";
foreach (var role in rolesIQueryable)
{
roles += role.rolesName + ",";
}
roles.Substring(0, roles.Length - 2);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
username, // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMinutes(30), // Date/time to expire
true, // "true" for a persistent user cookie
roles, // User-data, in this case the roles
FormsAuthentication.FormsCookiePath);// Path cookie valid for
// Encrypt the cookie using the machine key for secure transport
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(
FormsAuthentication.FormsCookieName, // Name of auth cookie
hash); // Hashed ticket
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
// Add the cookie to the list for outgoing response
HttpContext.Current.Response.Cookies.Add(cookie);
return true;
}
catch
{
return (false);
}
}
}
almaceno los papeles en mi base de datos con dos tablas: tabla: Rol que tiene las columnas: roleID y roleName y la tabla: UsersRoles que tiene las columnas: userID e roleID, esto hace posible múltiples roles para varios usuarios y es fácil hacer su propia lógica para agregar/eliminar roles de los usuarios Etcétera. Esto le permite usar [Authorize (Roles = "Super Admin")] por ejemplo. espero que esto ayude.
de edición: se olvidó de hacer la comprobación de la contraseña pero que acaba de agregar un caso en el método de inicio de sesión que comprueba si el nombre de usuario y la contraseña proporcionada cheques hacia arriba y si no se devuelve falso
Espera, ¿así que estás almacenando los nombres de roles en la cookie de autenticación? ¿No significa esto que el usuario puede poner cualquier función que quiera en su cookie de autenticación? Supongo que no importa porque tendrían que descifrar la cookie. – Pandincus
@Pandincus: Sí, esa es una de las desventajas de utilizar este método si el usuario logra descifrar la cookie, lo que se podría hacer es cifrar aún más las funciones y proporcionar una clave pública junto con la cookie para su posterior descifrado en el .asax. No es perfecto, pero hace el trabajo y no es tan complejo. – Joakim
- 1. Proveedor de membresía de asp.net personalizado
- 2. ASP.NET MVC Proveedor de membresía personalizado Error Web.config
- 3. ASP.NET Proveedor de membresía personalizado para aplicaciones muy grandes
- 4. ¿Cómo puedo adjuntar un proveedor de membresía personalizado en mi aplicación ASP.NET MVC?
- 5. oAuth Proveedor de membresía de ASP.NET
- 6. Extendiendo un proveedor de membresía personalizado
- 7. Inyección de dependencia con un proveedor de membresía personalizado
- 8. Agregar membresía grupal al proveedor de Membresía/Roles personalizado
- 9. Cómo implementar un proveedor de caché personalizado con ASP.NET MVC
- 10. Autenticación API web ASP.NET MVC 4 con proveedor de membresía
- 11. ¿Cómo crear un password de proveedor de membresía asp.net manualmente?
- 12. Inyectar en un proveedor de membresía personalizado con StructureMap
- 13. Proveedor de membresía de ASP.NET con EF
- 14. ASP.NET MVC Cómo administrar el contenido del usuario utilizando el proveedor de membresía ASP.NET
- 15. membresía de ASP.NET MVC 3 con MySQL
- 16. ASP.NET MVC: ¿alternativa al proveedor de funciones?
- 17. Cómo integrar el proveedor de membresía de IoC con ASP.NET MVC
- 18. membresía personalizada de ASP.NET MVC para principiantes
- 19. Implementación de proveedor de perfil personalizado en ASP.NET MVC
- 20. Membresía, Membresía Proveedor y Membresía ¿Relaciones con el usuario en ASP.NET?
- 21. ASP.NET MVC 3 Ninject suscripciones personalizado y proveedor de funciones
- 22. Algoritmo hash diferente para el proveedor de membresía ASP.NET?
- 23. Guardar un cambio de correo electrónico dentro del proveedor de membresía predeterminado en ASP.NET MVC
- 24. AccountController Ampliación: ASP.NET MVC membresía
- 25. ¿Cómo desactivo una cuenta con el proveedor de membresía ASP.NET?
- 26. Proporcionar funcionalidad de base de datos personalizada al proveedor de membresía de asp.net personalizado
- 27. Anulación de la membresía ASP.NET en ASP.NET MVC 4
- 28. ASP.NET MVC: autenticación/membresía de subdominio cruzado
- 29. Proveedor de membresía ASP.NET - Inicio de sesión único
- 30. Proveedor de membresía de ASP.NET Active Directory y proveedor de perfiles de SQL
¡la forma en que has explicado esto es sensacional! y apuesto a que ni siquiera estabas intentando tanto ... deberías considerar escribir publicaciones en el blog :). –
¡la forma en que has explicado esto es sensacional! y apuesto a que ni siquiera estabas intentando tanto ... deberías considerar escribir publicaciones en el blog :). –
gracias amigo, me alegro de que haya ayudado. me encuentro haciendo eso a menudo y al hacerlo lo entiendo mejor yo mismo :-) – danfromisrael