Uma preocupação sempre presente em qualquer sistema web é a segurança. E normalmente começamos resolvendo as questões relativas à autenticação dos usuários do sistema. Em um projeto AspNet MVC 4 isso pode ser gerenciado de maneira muito simples usando os recursos já disponíveis no framework. Primeiramente, vamos definir dois conceitos básicos: Autenticação e Autorização.

Explicando de maneira bem simples, Autenticação é o mesmo que identificar os usuários. Ou seja, as pessoas que estão utilizando o sistema são realmente quem dizem ser? Respondemos a esta pergunta utilizando os logins e senha, dessa forma garantimos que a se o usuário possui um login e também sabe a senha daquela login, então ele deve realmente ser quem diz ser…

Mas isso nos leva a outra questão, uma vez identificado, precisamos ainda garantir que os usuários não façam nada além do que lhes é permitido. Ou seja, na sua empresa provavelmente todos possuem seus crachás para passar pela portaria da empresa apresentando-o (Autenticação), mas uma vez dentro da empresa você não pode entrar na sala de recursos humanos e abrir os arquivos dos funcionários se você não fizer parte deste setor, ou ainda, entrar no setor financeiro e assinar um cheque a menos que você seja o responsável financeiro.  Separar as responsabilidades de cada usuário é papel da Autorização do seu sistema.

Autenticação

Na construção de um sistema de segurança de nosso aplicativo temos que começar separando os usuários autenticados (funcionários com crachás) dos usuários não autenticados (ou simplesmente, anônimos). Mas como podemos responder à essa pergunta simples: “O usuário esta autenticado?”. Obviamente, vamos precisar de alguma implementação que verifique os dados que o usuário informou (login e senha)… Então você vai fazer alguma query que verifique se os dados batem e então vai colocar os dados do usuário na sessão, cookie ou etc… não vamos entrar em detalhes, então para resumir, podemos afirmar que uma vez verificados os dados do usuário, o sistema vai armazenar a identidade do usuário na variável User.Identity (do próprio framework).

Daí você pode dizer… “Ok Paulovich… mas isso é fácil, basta fazer um ‘if’ testando o valor de User.Identity.IsAuthenticated”… Certo! Você está certíssimo, acontece que você não vai querer encher seu código de if. Então, para alcançar o mesmo objetivo podemos usar o atributo [Authorize] para ‘decorar’ nossas classes.

A grande sacada dos atributos de autenticação do MVC4 é que eles encapsulam um outro recurso: o “Action Filters”, e o tudo que você precisa saber sobre os “Action Filters” neste momento é que eles lhe permitem criar lógicas de filtragem antes e depois da execução de cada Action Method. É claro que você pode usar estes filtros para realizar várias coisas legais, mas vamos nos focar na solução do problema de segurança.

Como você já deve saber, toda execução server-side aplicações MVC é orientada à Controllers e Actions e é justamente nestes caras que precisamos atuar para definir as exigências de segurança.

Por exemplo, se quisermos que um Controller só seja executado por usuários autenticados, precisamos apenas decorar o controller com o atributo [Authorize] dessa forma:

[Authorize]
public class AutenticadoController : Controller
{
    ...
}

Fazendo isso, todos os Actions só poderão ser executados por usuários autenticados. Quando você quiser que algum action esteja disponível para todos os usuários, inclusive os usuários anônimos, basta decora-lo com o atributo [AllowAnonymous].

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        // bla bla bla.. seu código
        return View();
    }
}

Autorização

Uma vez resolvido o problema de autenticação, precisamos fazer outra pergunta: “Este usuário autenticado pode executar esta ação?”. Ou seja, autorização é determinar os “poderes” do usuário para então poder verificar se ele pode fazer o que está querendo fazer.

Novamente, você terá que implementar alguma lógica que possibilite relacionar um usuário à algum nível de segurança. Como no exemplo acima, vamos imaginar que o nível de segurança de cada usuário seja diretamente relacionado ao departamento a que ele pertence na empresa. Então teremos usuários dos departamentos: Financeiro, Recursos Humanos, Desenvolvimento, etc…

A primeira coisa a fazer é armazenar as informações dos níveis de segurança que o usuário possui em algum lugar que possamos acessar para fazer a verificação a cada nova ação que ele requisitar. Um bom local é um cookie. Abaixo um exemplo de como você pode gerar o cookie para guardar os níveis de segurança (roles).

public void CreateAuthorizeTicket(userId, roles){

	FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
	  1,
	  userId,  // Id do usuário é muito importante
	  DateTime.Now,
	  DateTime.Now.AddMinutes(30),  // validade 30 min tá bom demais
	  false,   // Se você deixar true, o cookie ficará no PC do usuário
	  roles);

	HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(authTicket));

	Response.Cookies.Add(cookie);

}

UsuarioDoSistema user = CheckUser(login, password); // funcao para retornar o usuário através de login e senha

int userId = user.Id; // 42, por exemplo
string roles = user.Roles; // O usuário pode ter mais de um perfil: "Financeiro,Administrativo";

CreateAuthorizeTicket(42, roles);

Beleza…! E agora? Agora vem a parte fácil… nós precisamos capturar o evento de Autentication_Request no global.asax para atribuir as permissões ao usuário da Thread dessa forma:

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
	if (HttpContext.Current.User == null) return;
	if (!HttpContext.Current.User.Identity.IsAuthenticated) return;
	if (HttpContext.Current.User.Identity is FormsIdentity)
	{
		var id = (FormsIdentity)HttpContext.Current.User.Identity;
		FormsAuthenticationTicket ticket = id.Ticket;
		string userData = ticket.UserData;
		string[] roles = userData.Split(',');
		HttpContext.Current.User = new GenericPrincipal(id, roles);
	}
}

Pronto! Tudo que você precisa fazer para utilizar os recursos de autorização é decorar seus controllers e actions com o nível exigido de acesso.

[Authorize]
public ActionResult Index()
{
	return View();
}

[Authorize(Roles = "Financeiro")]
public ActionResult Finance()
{
	return View();
}

[Authorize(Roles = "Administrativo")]
public ActionResult Admin()
{
	return View();
}

[Authorize(Roles = "Desenvolvimento")]
public ActionResult Develop()
{
	return View();
}

Existem muitas formas de realizar essa implementação, mas procurei mostrar da forma mais simples para que você possa aprender e implementar melhorias ao seu gosto. Segue também um Projeto de exemplo.

Lembrete!

Lembre-se de configurar o FormsAuthentication no seu web.config:

<system.web>    
    <authentication mode="Forms">
      <forms loginurl="~/PaginaDeLogin" defaulturl="~/PaginaPadraoAposLogar"></forms>
    </authentication>	
</system.web>

Um abraço!