Dei uma boa olhada na nova funcionalidade de autenticação e autorização para o ASP.Net MVC, e posso dizer que ficou bem legal. Gostei do que vi, ficou simples e fácil de aplicar. Assim como todas essas novas funcionalidades, esta está vindo também através de um Interception Filter. Basicamente o que o filtro faz é verificar se você está autenticado, e opcionalmente, autorizado a acessar uma determinada ação ou controller.
O atributo é o AuthorizeAttribute, e você pode ver o que ele está fazendo no repositório do fonte no Codeplex. Note que, basicamente, ele está verificando se o usuário está autenticado, olhando para a user.Identity.IsAuthenticated:
IPrincipal user = filterContext.HttpContext.User; if (!user.Identity.IsAuthenticated) { filterContext.Cancel = true; filterContext.Result = new HttpUnauthorizedResult(); return;
Nada de mais, certo? Para autorizar é mais ou menos a mesma coisa, ele pega a lista de usuários ou papéis (roles) e verifica:
if (!String.IsNullOrEmpty(Users)) { IEnumerable<string> validNames = SplitString(Users); bool wasMatch = validNames.Any(name => String.Equals(name, user.Identity.Name, StringComparison.OrdinalIgnoreCase)); if (!wasMatch) { filterContext.Cancel = true; filterContext.Result = new HttpUnauthorizedResult(); return; } } if (!String.IsNullOrEmpty(Roles)) { IEnumerable<string> validRoles = SplitString(Roles); bool wasMatch = validRoles.Any(role => user.IsInRole(role)); if (!wasMatch) { filterContext.Cancel = true; filterContext.Result = new HttpUnauthorizedResult(); } }
Além deste atributo, que faz o trabalho pesado de autenticação e autorização, há um controller para auxiliar no contato com o aplicativo em si. Ele se chama AccountController, e já vem no projeto. Há também algumas views que esse controle utiliza. Dêem uma olhada no Solution Explorer, com os itens novos destacados:
Já o controller em si traz os seguintes métodos:
Como podemos ver, ele tem ações para trocar senha, logar, deslogar, e criar um novo usuário (register). Ele não lista usuários, cria grupos e outras tarefas administrativas. Pelo que eu li nos blogs da Microsoft, eles esperam que tarefas administrativas sejam feitas de outra forma, e sugerem que no IIS 7 isso já é mais fácil. Isso pode querer dizer que não vai rolar um sistema de gestão de usuários no MVC. Para compensar isso há a boa notícia de que eles vão evoluir um pouco mais esse controlador e as views, permitindo trocar os mecanismos de autenticação e autorização, se não quisermos usar o membership do ASP.Net, que é onde o atributo [Authorize] e o controlador estão acoplados atualmente. Será possível estender este modelo de 2 formas então:
- Trocando o membership do ASP.Net por algum outro framework;
- Trocando o provider de membership do ASP.Net. Para permitir isso, o construtor do controlador já inicia com uma injeção de dependência bonita, dêem uma olhada:
16 public AccountController()
17 : this(null, null)
18 {
19 }
20
21 public AccountController(IFormsAuthentication formsAuth, MembershipProvider provider)
22 {
23 FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
24 Provider = provider ?? Membership.Provider;
25 }
Essa interface, IFormsAuthentication, é nova, e é parte do MVC. O MembershipProvider é o velho conhecido MembershipProvider do ASP.Net. Dessa forma, fica fácil injetar um outro provider, para testar, e até mesmo trocá-lo. Para arrancar de vez o Membership do ASP.Net (primeira opção acima), a recomendação até agora é refazer o controlador. Mas isso vai melhorar.
Vimos que há view para trocar senha, para fazer login e se cadastrar. Como fica? Vou mostrar um screenshots abaixo, mas antes fiz um controlador simples, onde um usuário normal só pode ver uma lista de categorias, e o usuário admin pode alterar. Vejam o controlador:
1 public class CategoriaController : Controller
2 {
3 [Authorize(Roles=“All,Admin”)]
4 public ActionResult Index()
5 {
6 return View(“Index”, (new Northwind2005Model.NorthwindEntities()).
7 Categories.ToList());
8 }
9
10 [Authorize(Roles = “Admin”)]
11 public ActionResult Edit(int id)
12 {
13 var northwind = new Northwind2005Model.NorthwindEntities();
14 var categoria = (from cat in northwind.Categories
15 where cat.CategoryID == id
16 select cat).First();
17 return View(categoria);
18 }
19
20 [Authorize(Roles = “Admin”)]
21 public ActionResult Update(int id)
22 {
23 var northwind = new Northwind2005Model.NorthwindEntities();
24 var categoria = (from cat in northwind.Categories
25 where cat.CategoryID == id
26 select cat).First();
27 BindingHelperExtensions.UpdateFrom(categoria, Request.Form);
28 northwind.SaveChanges();
29
30 return Index();
31 }
32 }
Naturalmente a ação index, que é a padrão, lista os usuários, mas antes eu preciso estar autenticado. Então, quando eu clico na aba de categorias, sou direcionado à view de login pelo controlador:
Após autenticar, por algum motivo, ele me redireciona de volta à Home (porque será?). Tenho que clicar novamente na aba de categorias que criei para finalmente ver as categorias, exibida pela ação index (notem o login aparecendo em destaque):
Mas eu loguei com um usuário comum. Ao tentar editar, sou direcionado ao login de novo, como se fosse para logar como admin. Logo como admin, ele volta à Home de novo (!?), navego até as categorias e tento editar. Agora já consigo editar e salvar. Essa é ação Edit, note mais uma vez o login no canto superior direito. Agora é o usuário admin:
Não gostei dessa história. Porque não posso ser direcionado de volta à mesma página, para exibir uma mensagem? Busquei uma forma simples. Ainda não há.
É possível ainda incluir um novo usuário via link de Register, ação também chamada Register (pode ser visto na primeira imagem do IE acima):
E trocar de senha:
Uma das coisas que achei mais interessantes está na ação de login: ela posta para si mesma, e dessa forma controla exibição de erros, como senha muito curta. Muito inteligente.
Conclusão dessa verificação do código de autorização e autenticação: com esse exemplo já dá para confirmar que o negócio funciona direitinho, mas precisa ainda evoluir um pouco em usabilidade e extensibilidade. Vamos aguardar agora o Preview 5, que deve sair daqui uns 2 meses.
Giovanni Bassi
Arquiteto e desenvolvedor, agilista, escalador, provocador. É fundador e CSA da Lambda3. Programa porque gosta. Acredita que pessoas autogerenciadas funcionam melhor e por acreditar que heterarquia é mais eficiente que hierarquia. Foi reconhecido Microsoft MVP há mais de dez anos, dos mais de vinte que atua no mercado. Já palestrou sobre .NET, Rust, microsserviços, JavaScript, TypeScript, Ruby, Node.js, Frontend e Backend, Agile, etc, no Brasil, e no exterior. Liderou grupos de usuários em assuntos como arquitetura de software, Docker, e .NET.