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.