Así que @thomas parece tener una buena respuesta, pero está envolviendo más su requisito de usar enumeraciones, tomando eso en Roles que IPricipal
entenderá.Mi solución es de abajo hacia arriba, así que puedes usar la solución de thomas encima de la mía para implementar IPrincipal
Realmente necesitaba algo similar a lo que quieres y siempre tenía miedo con la autenticación de formularios, (sí, también tienes miedo y Lo sé, pero escúchame) Así que siempre desarrollé mi propia autenticación barata con formularios, pero muchas cosas cambiaron mientras aprendía mvc (en las últimas dos semanas) La autenticación de formularios está muy separada y es muy flexible. Básicamente, no estás realmente usando formularios auth, sino que simplemente estás conectando tu propia lógica al sistema.
Así que aquí es cómo me enfrenté a esto, (tenga cuidado, yo soy un aprendiz yo mismo).
Resumen:
- vas para anular algunas de las formas clases de autenticación para autenticar a los usuarios es el propietario, (incluso se puede burlarse de esto)
- Estás a continuación, va a crear un
IIdentity
.
- cargar hasta
GenericPrincipal
con una lista de papeles en cuerdas (lo sé, no hay cuerdas mágicas ... seguir leyendo)
Una vez hecho lo anterior, MVC entiende suficiente para darle lo que quiere! Ahora puede usar [Authorize(Roles = "Write,Read")]
sobre cualquier controlador y MVC hará casi todo. Ahora, para las cadenas mágicas, todo lo que tiene que hacer es crear un envoltorio alrededor de ese atributo.
Respuesta larga
utiliza la plantilla de aplicación de Internet que viene con MVC, así que primero se comienza por la creación de proyectos MVC, en el nuevo cuadro de diálogo, supongamos que desea una aplicación de Internet .
Al verificar la aplicación, tendrá una clase principal que anula la autenticación de formularios. IMembershipService
Elimine la variable local ProviderProvider __provider_ y en esta clase al menos agregue lógica en el método ValidateUser
. (Intente agregar una autenticación falsa a un usuario/pase) También vea la aplicación de prueba v predeterminada creada en VS.
Implementar IIdentity
public class MyIdentity : IIdentity
{
public MyIdentity(string username)
{
_username = username;//auth from the DB here.
//load up the Roles from db or whatever
}
string _username;
public User UserData { get; set; }
#region IIdentity Members
public string AuthenticationType
{
get { return "MyOwn.Authentication"; }
}
public bool IsAuthenticated
{
get { return true; }
}
public string Name
{
get { return _username; }
}
#endregion
public string[] Roles
{
get
{
return //get a list of roles as strings from your Db or something.
}
}
}
Recuerde que todavía estamos utilizando la plantilla de aplicación de Internet por defecto que viene con un proyecto de MVC.
Así que ahora AccountController.LogOn() debe tener este aspecto:
[HttpPost]
public virtual ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(model.UserName, model.RememberMe, 15);
string encTicket = FormsAuthentication.Encrypt(ticket);
this.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
Así que lo que está haciendo es establecer un boleto formas como una sesión y luego vamos a leer de él en cada petición como esto: Pon esto en Global.asax.cs
public override void Init()
{
this.PostAuthenticateRequest += new EventHandler(MvcApplication_PostAuthenticateRequest);
base.Init();
}
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
string encTicket = authCookie.Value;
if (!String.IsNullOrEmpty(encTicket))
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(encTicket);
MyIdentity id = new MyIdentity(ticket.Name);
//HERE is where the magic happens!!
GenericPrincipal prin = new GenericPrincipal(id, id.Roles);
HttpContext.Current.User = prin;
}
}
}
he hecho una pregunta uno cómo es eficiente y corregir el método anterior era here.
Ok ahora Huy, se puede decorar sus controladores de la siguiente manera: [Authorize(Roles="RoleA,RoleB")]
(más en las cadenas posteriores)
Theres un pequeño problema aquí, si usted adorna su controlador con AuthorizeAttribute
, y el usuario conectado no tiene un permiso particular, en lugar de decir "acceso denegado" de forma predeterminada, el usuario será redirigido a la página de inicio de sesión para iniciar sesión de nuevo. Puede solucionar esto así (pellizqué esto desde una respuesta SO):
public class RoleAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// Returns HTTP 401
// If user is not logged in prompt
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(filterContext);
}
// Otherwise deny access
else
{
filterContext.Result = new RedirectToRouteResult(@"Default", new RouteValueDictionary{
{"controller","Account"},
{"action","NotAuthorized"}
});
}
}
}
Ahora todo lo que hacer es añadir otra envoltura alrededor de la AuthorizeAttribute
para soportar fuertes tipos que se traducirán en los que las cadenas principales espera. See this article for more.
Planeo actualizar mi aplicación para usar tipos fuertes más tarde, actualizaré esta respuesta a continuación.
Espero que haya sido útil.
¿No es este tipo de amplio? – jfar
@jfar - ¿Cómo es esto amplio ...? – TheCloudlessSky
Bueno, primero es contradictorio. Usted dice que debe usar atributos y luego pide alternativas de atributos. Luego dices que necesitas usar atributos, pero no quieres cadenas mágicas o enumeraciones, así que estás muy limitado allí. Está solicitando un sistema de permisos basado en la herencia, que puede o no usar atributos, no puede usar enumeraciones, que debe traducirse en atributos que de alguna manera interactúan con MVC y que también se almacenan fácilmente en la base de datos. Tocando muchas capas aquí. – jfar