ASP.NET MVC - Autorização Refactor
-
16-09-2019 - |
Pergunta
O problema que vejo com esse código, é que ele vai ser reutilizado um monte; qualquer coisa que está sendo editado / criado por um usuário autenticado (exceto para administradores do site) só terá acesso a um seus "estúdios" objetos.
A minha pergunta a todos vocês; como você re-fator isso para a camada de serviço pode ser abstraída a partir do conhecimento do cliente. Tenho a intenção de reutilizar a camada de serviço em um aplicativo de desktop stand-alone mais tarde.
Por favor, lançar alguma luz sobre os meus caminhos errados! Eu aprecio muito isso.
AuthorizeOwnerAttribute.cs (AuthorizeAttribute)
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// Get the authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = httpContext.Request.Cookies[cookieName];
// If the cookie can't be found, don't issue the ticket
if (authCookie == null) return false;
// Get the authentication ticket and rebuild the principal & identity
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
string[] userData = authTicket.UserData.Split(new[] { '|' });
int userId = Int32.Parse(userData[0]);
int studioID = Int32.Parse(userData[1]);
GenericIdentity userIdentity = new GenericIdentity(authTicket.Name);
WebPrincipal userPrincipal = new WebPrincipal(userIdentity, userId, studioID);
httpContext.User = userPrincipal;
return true;
}
Dentro do meu "Usuário" Controller anexar esse atributo para qualquer método que requer um proprietário
[AuthorizeOwner]
public ActionResult Edit(int Id)
{
IUser user = userService.GetById(HttpContext.User, Id);
return View(user);
}
Agora, no meu serviço camada é onde eu estou verificando o passado para baixo IPrincipal se ele tem acesso ao objeto que está sendo solicitado. Este é o lugar onde ele está ficando mau cheiro:
UserService.cs
public IUser GetById(IPrincipal authUser, int id)
{
if (authUser == null) throw new ArgumentException("user");
WebPrincipal webPrincipal = authUser as WebPrincipal;
if (webPrincipal == null) throw new AuthenticationException("User is not logged in");
IUser user = repository.GetByID(id).FirstOrDefault();
if (user != null)
{
if (user.StudioID != webPrincipal.StudioID) throw new AuthenticationException("User does not have ownership of this object");
return user;
}
throw new ArgumentException("Couldn't find a user by the id specified", "id");
}
Solução
Eu não tenho certeza eu estaria armazenando os IDs reais no cookie, que é um pouco demasiado exposta. Eu estaria mais inclinado a usar o hash de sessão para armazenar os dados mantendo-se assim no servidor e não expostos.
Eu também usar o Modelo (passando o ID do usuário) para determinar quais objetos para retornar, ou seja, aqueles que têm um studioID correspondente. Dessa forma, o controlador apenas iria ter que chamar "GetObjects (id int)", se eles não têm acesso a qualquer coisa então você obtém um nulo ou uma coleção de volta vazio. Que se sente mais limpo para mim.