Website com Controle de Acesso usando ASP.NET MVC, Bootstrap e Razor

Nesse artigo será apresentado como desenvolver uma aplicação web com controle de usuário e perfil. Será criado o website utilizando o ASP.NET MVC, Bootstrap e o Razor.

Quando pensamos em desenvolver um site temos que pensar primeiro em sua segurança. A primeira segurança que vem em nossas cabeças é colocar um controle de acesso a usuários. Pensamos que com isso o site já está protegido, mais esquecemos de uma coisa importante que é o que o usuário vai ter acesso. Com esse pensamento muitos desenvolvedores criam níveis de acesso ao site para determinados usuário, o que caracteriza o perfil.

No projeto website deste artigo será criada uma tabela de controle de acesso, onde teremos os dados do usuário para o acesso e o campo de perfil, que será estático e não terá tabela para serem criados e configurados novos perfis. Por ser estático, veremos como atribuir permissão a uma tela inteira ou a um método, isso para um usuário ou atribuindo o perfil que pode ter acesso.

Para o desenvolvimento será utilizado o Visual Studio 2013 e o banco de dados SQL Server 2012 (consulte a seção Links para ver os respectivos links).

Controle de Acesso

Criaremos primeiro o Banco de Dados que será responsável por armazenar a tabela de acesso e para isso usaremos o seguir:

CREATE DATABASE DEVMEDIA;

Após a criação do banco de dados criamos a tabela de ACESSO, responsável por armazenar as informações do acesso, conforme a Listagem 1.

USE DEVMEDIA CREATE TABLE ACESSO( ID_LOGIN INT IDENTITY NOT NULL, EMAIL VARCHAR(100), SENHA VARCHAR(100), ATIVO CHAR(1), PERFIL VARCHAR(15), NOME VARCHAR(30), SOBRENOME VARCHAR(30) )
Listagem 1. Tabela de Acesso

Após a criação da tabela iremos executar o script de insert para a criação dos usuários no site, conforme a Listagem 2.

INSERT INTO ACESSO (EMAIL, SENHA, ATIVO, PERFIL, NOME, SOBRENOME) VALUES ('admin@admin.com', '123456', 'S', 'Administrador', 'Admin', 'Sistema') INSERT INTO ACESSO (EMAIL, SENHA, ATIVO, PERFIL, NOME, SOBRENOME) VALUES ('user@user.com', '123456', 'S', 'Usuario', 'User', 'Sistema')
Listagem 2. Criação dos usuários

Agora no Visual Studio iremos criar o projeto, conforme os passos da Figura 1.

Figura 1. Criação do projeto

Escolha a opção ASP.NET Web Application e dê o nome de Controle Acesso. Em seguida escolha o tipo de projeto que será criado que, no nosso caso, será um projeto Empty (Vazio), e utilizaremos a estrutura do MVC, como mostra a Figura 2. Não podemos esquecer de desmarcar a opção do Microsoft Azure, pois não iremos criar um site já hospedado.

Figura 2. Tipo de projeto

Agora criaremos a conexão do banco de dados utilizando o Entity Framework. Para isso, basta clicar com o botão direito do mouse na pasta Model à Opção Add à New Item e a tela igual a Figura 3 aparecerá. Nela escolheremos a opção Data no navegador, que está na lateral esquerda, e no quadrado à direita escolha a opção ADO.NET Entity Data Model. O nome do projeto será ControleAcesso.cs.

Figura 3. Projeto Entity Framework

Na próxima tela escolha a opção EF Designer from DataBase, que criará um projeto a partir de um banco de dados que iremos escolher. Aparecerá na próxima tela o botão “New Connection” e, ao clicar nele, irá aparecer a tela semelhante à Figura 4 para preencher algumas informações para conexão do banco de dados.

Figura 4. Configuração de uma nova conexão com o banco de dados

No campo Server name preencha com o nome do servidor do banco de dados. Caso esteja instalado localmente pode utilizar o nome do computador ou o localhost.

Não esqueça de marcar a opção de autenticação com o banco de dados: caso não tenha um usuário ou senha do banco basta escolher a primeira opção. Caso contrário, use a opção Use SQL Server Authentication para informar o usuário e senha de acesso ao bando de dados.

Após o preenchimento de todos os campos e escolhido o banco de dados, basta clicar em Test Connection: caso esteja tudo ok irá aparecer a mensagem Test Connection Succeeded. Ao final clique no botão OK.

Voltando para a tela de configuração da conexão, não esqueça de marcar a opção “Yes, include the sensitive data in the connection string” para gravar a senha na connection string no WebConfig do projeto. Clique no botão Next e escolha a opção Entity Framework 6.x.

Na Figura 5 selecione apenas a opção Tables e clique em Finish.

Figura 5. Finalizando a criação do modelo

Com isso, o Model do seu banco de dados com todas as configurações já está pronto para o uso. Na Figura 6 vemos a conexão que foi criada no Entity Framework.

Figura 6. Conexão com EF

Agora vamos até a pasta do Controllers e criar um novo controle. Para isso basta clicar com o botão direito do mouse em cima da pasta Controllers à Add à Controller. Escolha o tipo MVC 5 Controller – Empty e dê o nome de HomeController.

Agora precisamos criar a Index do controlador. Para isso, basta abrir o HomeController que foi criado e ir no método public ActionResult Index() e clicar com o botão direito do mouse em cima de Index e escolher a opção Add View.

Na nova tela preencha as seguintes informações:

Dentre as Opções temos:

Crie também o controlador responsável pela parte de Login chamado AccountController. Este terá um método chamado public ActionResult Index (), mas iremos renomear este para Login ().Crie a view referente a nossa tela de login usando as mesmas configurações da tela de Home.

Antes de fazermos qualquer coisa na tela de login iremos fazer a instalação do framework Bootstrap. Para isso, iremos no nosso projeto e clicaremos com o botão direito do mouse sobre e escolher a opção Manage Nuget Packages, como ilustra a Figura 7.

Figura 7. Instalação de um novo plug-in

Busque na pesquisa por bootstrap e pressione enter. Ela irá carregar vários plug-ins que podem ser utilizados, mas iremos escolher o bootstrap que apareceu primeiro, como mostra a Figura 8.

Figura 8. Instalação do plug-in Bootstrap

Para começar a tela de login vamos utilizar um CSS padrão presente na Listagem 3. Clique com o botão direito do mouse na pasta Content à Add à Style Sheet, e coloque o nome devmedia_estilo. Esse refere-se a tela de login aonde iremos criar um quadrado centralizado com dois Input Text e um Botão. Foi disponibilizado também o CSS presente na Listagem 3.

body { background-color: #f0f0f0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #313131; line-height: 1; padding: 5px; } { width: 100%; height: 100%; background-color: #2D333B; } .form-login { max-width: 450px; max-height: 350px; margin-left: auto; margin-right: auto; padding: 10px; border-radius: 10px; margin-top: 10%; } .form-login input { margin-bottom: 10px; } .btn { display: inline-block; padding: 6px 12px; border: 2px solid #ddd; color: #ddd; text-decoration: none; font-weight: 700; text-transform: uppercase; margin: 15px 5px 0; transition: all .2s; min-width: 100px; text-align: center; font-size: 14px; } .btn:hover, .btn.hover { background: #ddd; color: #777; } .btn.btn-lg { padding: 10px 16px; font-size: 18px; } .btn.btn-sm { padding: 5px 10px; font-size: 12px; } .btn.btn-xs { padding: 1px 5px; font-size: 12px; padding: 1px 5px; font-size: 12px; } .btn.primary { border-color: #3498db; color: #3498db; } .btn.primary:hover, .btn.primary.hover { background: #3498db; color: #fff; } .btn.danger { border-color: #e74c3c; color: #e74c3c; } .btn.danger:hover, .btn.danger.hover { background: #e74c3c; color: #fff; } .btn.success { border-color: #27ae60; color: #27ae60; } .btn.success:hover, .btn.success.hover { background: #27ae60; color: #fff; } .btn.warning { border-color: #f1c40f; color: #f1c40f; } .btn.warning:hover, .btn.warning.hover { background: #f1c40f; color: #fff; } .btn.black { border-color: #34495e; color: #34495e; } .btn.black:hover, .btn.black.hover { background: #34495e; color: #fff; } .btn.black { border-color: #34495e; color: #34495e; } .btn.black:hover, .btn.black.hover { background: #34495e; color: #fff; } .btn.info { border-color: #5bc0de; color: #5bc0de; } .btn.info:hover, .btn.info.hover { background: #5bc0de; color: #fff; } .btn.clear { border-color: #777; color: #777; } .btn.clear:hover, .btn.clear.hover { background: #777; color: #fff; } }
Listagem 3. CSS da tela login

Vá a view de login e insira o código da Listagem 4. Em seguida compile o site.

@model Controle_Acesso.Models.ACESSO @{ Layout = null; } <link href="~/Content/bootstrap.min.css" rel="stylesheet" /> <link href="~/Content/devmedia_estilo.css" rel="stylesheet" /> <script src="~/scripts/jquery-1.10.2.js"></script> <script src="~/scripts/bootstrap.min.js"></script> @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal" })) { @Html.AntiForgeryToken(); @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div class="container"> <div class="form-login"> <div class="panel panel-default"> <div class="panel-heading"> <div class="panel-title">Login do Sistema</div> </div> <div class="panel-body"> <div id="result" class="alert alert-danger col-sm-12"> </div> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span> @Html.EditorFor(model => model.EMAIL, new { htmlAttributes = new { @class = "form-control input-lg", placeholder = "E-mail", autofocus = true } }) @Html.ValidationMessageFor(model => model.EMAIL, "", new { @class = "text-danger" }) </div> <div class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span> @Html.EditorFor(model => model.SENHA, new { htmlAttributes = new { @class = "form-control input-lg", placeholder = "Senha" } }) @Html.ValidationMessageFor(model => model.SENHA, "", new { @class = "text-danger" }) </div> <div class="form-group"> <div class="col-sm-12 controls"> <input type="submit" value="Acessar" class="btn primary btn-lg" /> </div> </div> </div> </div> </div> </div> }
Listagem 4. CSS da view Login

A compilação resultará na tela presente na Figura 9.

Figura 9. Tela de login

Precisamos alterar a URL para http://seusite/Home, assim abrirá a página home normalmente.

Criaremos agora a classe de ROLE para condicionar no projeto quem pode ter acesso ou não a uma determinada tela ou ação.

Para isso vai até a pasta model e crie uma nova classe chamada Role.cs. Ela vai fazer herança com a RoleProvider, mas para isso, na classe Role Provider declare o Using System.Web.Security:

public class Roles : RoleProvider { }

Após efetuar a herança copie o código da Listagem 5 e cole no projeto para implementar da classe RoleProvider.

public override void AddUsersToRoles(string[] usernames, string[] roleNames) { throw new NotImplementedException(); } public override string ApplicationName { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } public override void CreateRole(string roleName) { throw new NotImplementedException(); } public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) { throw new NotImplementedException(); } public override string[] FindUsersInRole(string roleName, string usernameToMatch) { throw new NotImplementedException(); } public override string[] GetAllRoles() { throw new NotImplementedException(); } public override string[] GetRolesForUser(string username) { DEVMEDIAEntities db = new DEVMEDIAEntities(); string sRoles = db.ACESSO.Where(p => p.EMAIL == username).FirstOrDefault().PERFIL; string[] retorno = { sRoles }; return retorno; throw new NotImplementedException(); } public override string[] GetUsersInRole(string roleName) { throw new NotImplementedException(); } public override bool IsUserInRole(string username, string roleName) { throw new NotImplementedException(); } public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) { throw new NotImplementedException(); } public override bool RoleExists(string roleName) { throw new NotImplementedException(); }
Listagem 5. Classe RoleProvider

Abra o controlador HomeController e adicione o código Authorize logo no início da classe, isso porque queremos bloquear o acesso a página inteira. Caso queira restringir o acesso a alguns métodos basta colocar o Authorize em cima do método.

O Authorize está sem roles ainda, então todos os usuários que forem autenticados terão acesso a página ou método. Caso queira restringir para algum perfil ou perfis basta colocar o comando:

[Authorize(Roles = "Administrador")]

Assim, isso está condicionando a apenas Administradores o acesso a página Home.

Utilizando o comando a seguir:

[Authorize(Roles = "Administrador, Usuario")]

Este está condicionando o acesso aos perfis Administrador ou Usuário. Assim, o Authorize ficará como na Listagem 6.

[Authorize] public class HomeController : Controller { // GET: Home public ActionResult Index() { return View(); } }
Listagem 6. Código do Authorize

Antes de compilar temos que fazer uma alteração no WebConfig da aplicação e adicionar as tags presentes na Listagem 7 dentro da tag .

<authentication mode="Forms"> <forms loginUrl="~/Account/Login" timeout="2880" /> </authentication> <roleManager enabled="true" defaultProvider="Roles"> <providers> <clear/> <add name="Roles" type="Repositorio_Dados.Models.Roles"/> </providers> </roleManager>
Listagem 7. Tags do webConfig

A primeira tag authentication vai redirecionar para a página que estamos colocando na tag forms, sempre que encontrar um authorize e o usuário não estiver autenticado ou não tiver permissão.

A tag roleManager vai olhar para a nossa classe que foi criada para controle de permissão (Roles) e vai cuidar da validação de alguma permissão. Aqui, é importante observar que o caminho informado nessa tag refere-se ao nome da classe, incluindo seu namespace, e não necessariamente o caminho do arquivo no qual a classe está contida.

Agora vamos fazer a autenticação do usuário. Para isso vamos acessar o controller AccountController. Nele encontraremos o seguinte código:

public ActionResult Index() { return View(); }

Altere o mesmo e insira esse código da Listagem 8.

/// <param name="returnURL"></param> /// <returns></returns> public ActionResult Login(string returnURL) { /*Recebe a url que o usuário tentou acessar*/ ViewBag.ReturnUrl = returnURL; return View(new ACESSO()); }
Listagem 8. Novo conteúdo do controller AccountController

Implementamos o método login, que é responsável por redirecionar para a View de acesso. Ele pede como parâmetro uma returnURL que armazena qual é a URL atual para ser redirecionado após a autenticação.

Na Listagem 9 vemos o método que faz a validação e a autenticação do usuário.

/ <param name="login"></param> / <param name="returnUrl"></param> / <returns></returns> [HttpPost] [ValidateAntiForgeryToken] public ActionResult Login(ACESSO login, string returnUrl) { if (ModelState.IsValid) { using (DEVMEDIAEntities db = new DEVMEDIAEntities()) { var vLogin = db.ACESSO.Where(p => p.EMAIL.Equals(login.EMAIL)).FirstOrDefault(); /*Verificar se a variavel vLogin está vazia. Isso pode ocorrer caso o usuário não existe. Caso não exista ele vai cair na condição else.*/ if (vLogin != null) { /*Código abaixo verifica se o usuário que retornou na variavel tem está ativo. Caso não esteja cai direto no else*/ if (Equals(vLogin.ATIVO, "S")) { /*Código abaixo verifica se a senha digitada no site é igual a senha que está sendo retornada do banco. Caso não cai direto no else*/ if (Equals(vLogin.SENHA, login.SENHA)) { FormsAuthentication.SetAuthCookie(vLogin.EMAIL, false); if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") && !returnUrl.StartsWith("//") && returnUrl.StartsWith("/\\")) { return Redirect(returnUrl); } /*código abaixo cria uma session para armazenar o nome do usuário*/ Session["Nome"] = vLogin.NOME; /*código abaixo cria uma session para armazenar o sobrenome do usuário*/ Session["Sobrenome"] = vLogin.SOBRENOME; /*retorna para a tela inicial do Home*/ return RedirectToAction("Index", "Home"); } /*Else responsável da validação da senha*/ else { /*Escreve na tela a mensagem de erro informada*/ ModelState.AddModelError("", "Senha informada Inválida!!!"); /*Retorna a tela de login*/ return View(new ACESSO()); } } /*Else responsável por verificar se o usuário está ativo*/ else { /*Escreve na tela a mensagem de erro informada*/ ModelState.AddModelError("", "Usuário sem acesso para usar o sistema!!!"); /*Retorna a tela de login*/ return View(new ACESSO()); } } /*Else responsável por verificar se o usuário existe*/ else { /*Escreve na tela a mensagem de erro informada*/ ModelState.AddModelError("", "E-mail informado inválido!!!"); /*Retorna a tela de login*/ return View(new ACESSO()); } } } /*Caso os campos não esteja de acordo com a solicitação retorna a tela de login com as mensagem dos campos*/ return View(login); }
Listagem 9. Método de validação

Na linha 08 o método valida os campos da tela e caso esteja tudo de acordo com as regras, ele retorna true e passa para o próximo passo. Caso contrário, ele cai no else do if*/

Na linha 10 o método cria a variável db, que recebe o EF. Ele é utilizado para não termos que destruir o objeto que foi criado. O mesmo, por padrão, quando deixa de ser utilizado é eliminado memória.

A variável da linha 12 é responsável por receber os dados da tabela de Acesso, que é retornado após a condição where. Como parâmetro usamos a variavel login.Email, que é o retorna da tela de login.

A partir da linha 25 temos que caso o usuário e senha estejam validados e o usuário esteja ativo, ele faz a autenticação do usuário gravando no Cookie a senha do usuário e o parâmetro False, que é utilizado pois sempre que o usuário fechar o navegador e abrir ele pede a autenticação novamente. Caso o parâmetro seja true, sempre que o usuário entrar no navegador e digitar a página, ele já vai entrar direto sem autenticação. Isso é um risco, pois pessoas mal-intencionadas consegue descriptografar o cookie e consegue pegar o usuário gravado.

O if da linha 26 faz a verificação da string do site, isso por causa da segurança na hora do retorno. Caso o parâmetro returnURL seja maior que 1, significa que existe uma string. Após isso, ele verifica se inicia com uma barra, que é o padrão. Caso retorne duas barras é errado e ele não valida, e por último ele verifica.

Agora, para efetuarmos os demais testes, criaremos a classe Acesso completa utilizando o Scaffold.

O Scaffold é capaz de gerar telas e controladores para as operações de inserção, leitura, alteração e remoção, chamado (CRUD), a partir de uma entidade. Os controladores gerados podem utilizar as funcionalidades do Entity Framework para interagir como banco de dados.

Para isso, clique com o botão direito em cima da pasta Controllers, escolha a opção ADD e depois Controler, que irá abrir uma tela parecida com a Figura 10.

Figura 10. Tela do Scaffold

Escolha a opção que está com a seta na frente MVC 5 Controller with views, using Entity Framework.

Após escolhida a opção solicitada irá abrir uma tela parecida com a Figura 11.

Figura 11. Tela do Controller

Na tela da Figura 11 temos os seguintes campos:

Após efetuado o preenchimento de todos os dados iremos clicar em ADD e assim criaremos o Controller AcessoControler com as Views (Create, Delete, Details, Edit e Index). A Figura 12 ilustra como ficará.

Figura 12. Estrutura do Controller e Views Acesso

Para iniciarmos os testes na Views Home iremos adicionar o código da Listagem 10.

@{ Layout = null; } <div class="container" > <div class="row" > <h2>DEVMEDIA</h2> @if (Session["Nome"] != null) { <p><h3>Bem vindo ao sistema</h3> <h1> @Session["Nome"].ToString() @Session["Sobrenome"].ToString()</h1></p> <p>@Html.ActionLink("Cadastro de Acesso", "Index", "Acesso")</p> } </div> </div>
Listagem 10. Views Home

Após inserir o código na View e compilarmos, o resultado será igual a Figura 13.

Figura 13. Tela do Home

Após executar e ter o resultado informado, basta clicar no link Cadastro de Acesso, assim, a página Index será exibida como está no ActionLink. Essa classe traz a lista de usuários cadastrados, como ilustra a Figura 14.

Figura 14. Index do Controller Acesso

Agora vamos aplicar a autorização para alguns métodos como o Edit e o Delete.

Iremos informar no código que só terá acesso a essas telas se o usuário for administrador, caso não seja, iremos redirecionar para a tela de Login. Para isso, colocaremos o método [Authorize(Roles = "Administrador")] em cima do método Edit e Delete, como ilustra as Listagens 11 e 12.

[Authorize(roles = “Administrador”)]</p> [Authorize(roles = “Administrador”)] public ActionResult Edit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatus.BadRequest); } ACESSO aCESSO = db.ACESSO.Find(id); If (aCESSO == null) { return HttpNotFoud(); } return View(aCESSO); } [Authorize(Roles = “Administrador”)] [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(Bind(Include = “ID_LOGIN, EMAIL, SENHA, ATIVO, PERFIL, NOME, SOBRENOME”)] ACESSO aCESSO) { if (ModelState.IsValid) { db.Entry(aCESSO).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction(“Index”); } return View(aCESSO); }
Listagem 11. Método Edit

No controler Acesso encontraremos dois métodos Edits: o primeiro trata-se de acesso a tela de editar e o segundo método Edit é a ação executada ao clicar no botão de Save da tela de Edit.

[Authorize(Roles = “Administrador”)] public ActionResult Delete(int? id) { if (id ==null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } ACESSO aCESSO = db.ACESSO.Find(id); if (aCESSO == null) { return HttppNotFound(); } return View(aCESSO); } [Authorize(Roles = “Administrador”)] [HttpPost, ActionName(“Delete”)] [ValidateAntiForgeryToken] public ActionResult DeleteConfirmed(int id) { ACESSO aCESSO = db.ACESSO.Find(id); db.ACESSO.Remove(aCESSO); db.SaveChanges(); return RedirectToAction(“Index”); }
Listagem 12. Método Delete

No controller Acesso encontraremos dois métodos delete: o primeiro trata-se de acesso a tela de delete e o segundo método é a ação ao clicar no botão de Save da tela de Edit.

Após a alteração, basta salvar o projeto, compilar novamente e efetuar os testes na tela com o usuário e perfil de Administrador clicando em editar e delete. Em seguida, faça o teste com o usuário e perfil de Usuário e verá que sempre que ao clicar em editar ou delete será redirecionado para a tela de Login.


Saiu na DevMedia!

  • JSF e Hibernate: Como implementar um CRUD: Neste curso você aprenderá a construir uma aplicação de cadastro de lembretes, que gravará essas informações em um banco de dados MySQL.
  • ASP.NET Web API e OData: Como criar filtros e ordenação: Neste microexemplo veremos como utilizar o pacote OData para adicionar funcionalidades de filtro, ordenação, paginação e seleção de campos no ASP.NET Web API. Confira!
  • O que é Java?: Neste curso você aprenderá o que é o Java, tecnologia para desenvolvimento de software mais utilizada pelos programadores em todo o mundo.

Saiba mais sobre ASP.NET ;)

  • ASP.NET MVC: Neste Guia de Referência você encontrará o conteúdo que precisa para aprender a desenvolver aplicações web com o framework ASP.NET MVC e a linguagem C#.
  • ASP.NET Web API: Neste Guia de Referência você encontrará o conteúdo que precisa para aprender a desenvolver web services RESTful com o framework ASP.NET Web API e a linguagem C#.

Artigos relacionados