none
usando membership provider personalizado RRS feed

  • Pergunta

  • Tenho um banco de dados com tabelas de usuarios e permissoes esse banco eu uso nas aplicações webforms, como uso esse mesmo banco de dados no mvc para ter os benefícios do authorize nas views ?
    Junior
    sexta-feira, 6 de maio de 2011 19:10

Respostas

  • Júnior,

    A pasta onde os arquivos das ActionFilter (classes) ficam não faz muita diferença, o importante é o namespace que deve corresponder ao da sua aplicação.

    Quanto à modificar a view login para utilizar a sua basta apagar todas as Action e inserir as suas.

    No meu caso utilizo assim:

      public class AccountController : Controller
      {
        private Domain _domain;
    
        public HomeController()
        {
          _domain = new Domain();
        }
    
        public ActionResult Index()
        {
          if (User.Identity.IsAuthenticated)
            return RedirectToAction("Index", "Menu");
          else
            return View();
        }
    
        [HttpPost]
        public ActionResult Index([Bind(Exclude = "Id")]User user)
        {
          if (ModelState.IsValid)
          {
            if (_domain.ValidateUser(user.Login, user.Password))
            {
              FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "Administrador", DateTime.Now, DateTime.Now.AddMinutes(30), false, "admin", FormsAuthentication.FormsCookiePath);
    
              //For security reasons we may hash the cookies
              string hashCookies = FormsAuthentication.Encrypt(ticket);
              HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashCookies);
    
              // add the cookie to user browser
              Response.Cookies.Add(cookie);
    
              return RedirectToAction("Index", "Menu");
    
            }
            else
            {
              ModelState.AddModelError("login", "Dados de login incorretos!");
              return View();
            }
          }
          else
          {
            return View();
          }
        }
    }
    

    • Marcado como Resposta Junior_luiz quarta-feira, 11 de maio de 2011 11:45
    terça-feira, 10 de maio de 2011 17:21
    Moderador
  • Ok, entendi o que você está fazendo. Como você pode ver não utilizo o MembershipProvider para buscar o usuário dentro do método RoleProvider.GetRolesForUsers, tenho uma camada de acesso a dados que retorna o usuário. No seu método GetRolesForUsers utilize um objeto de acesso a dados ou faça:

    db.usuarios.FirstOrDefault(u => u.Nome = username) que retorna seu usuário (db.usuarios).

     


    Atenciosamente, Paulo R. Pereira de Souza
    http://paulosouza.net
    E-mail: paulorpereirasouza@hotmail.com. twitter facebook linkedin
    • Marcado como Resposta Junior_luiz quarta-feira, 11 de maio de 2011 11:44
    terça-feira, 10 de maio de 2011 20:09

Todas as Respostas

  • Junior você deve criar um CustomMembershipProvider que extende de MembershipProvider e um CustomRoleProvider que extende CustomRoleProvider, o método RoleProvider.GetRolesForUser(string username) sempre é chamado quando você utiliza o atributo Authorize ou chama Context.User.IsInRole("Admin") por exemplo. Deve fazer as modificações necessárias no arquivo de configuração para utilizar a sua customização por ex:

    <membership defaultProvider="CustomMembership">
          <providers>
            <clear/>
            <add name="CustomMembership" applicationName="SuaEmpresa.SuaAplpication.Web" type="SuaEmpresa.Web.Security.CustomMembershipProvider, SuaEmpresa.Web"/>
          </providers>
        </membership>
        <roleManager enabled="true" defaultProvider="CustomRoles">
          <providers>
            <clear/>
            <add name="CustomRoles" applicationName="SuaEmpresa.SuaAplpication.Web" type="SuaEmpresa.Web.Security.CustomRoleProvider, SuaEmpresa.Web"/>
          </providers>
        </roleManager>

    Atenciosamente, Paulo R. Pereira de Souza
    http://paulosouza.net
    E-mail: paulorpereirasouza@hotmail.com. twitter facebook linkedin
    segunda-feira, 9 de maio de 2011 14:55
  • Paulo, obrigado por responder, estou estudando mvc e em webforms tenho uma tabela com usuario, permissoes e acesso, mais não está na estrutura do ASPNETDB, preciso ter a mesma estrutura ? e no caso, tenho uma extranet que já está em produção feita em webforms e estou fazendo a mesma em mvc, e gostaria de usar o banco existente pois já tenho todos os usuários cadastrados, e achei muito interessante a parte do authorize nas páginas mvc, para ter acesso a essa facilidade do authorize nas páginas preciso ter a mesma esturtura do ASPNETDB ?
    Junior
    segunda-feira, 9 de maio de 2011 17:08
  • Não precisa ter a mesma estrutura. Só corrigingo o post anterior o método é IsInRole, estava HasPermission.
    Atenciosamente, Paulo R. Pereira de Souza
    http://paulosouza.net
    E-mail: paulorpereirasouza@hotmail.com. twitter facebook linkedin
    segunda-feira, 9 de maio de 2011 18:26
  • vc sabe onde tem algum tutorial ?
    Junior
    segunda-feira, 9 de maio de 2011 19:42
  • Na epoca que estudei autorização com asp .net utilizei diversas fontes, o livro Pro ASP .NET 4, no msdn tem muita documentação também foi uma de minhas fontes, de forma geral a uma infinidade de fontes na internet sobre o assunto.


    Atenciosamente, Paulo R. Pereira de Souza
    http://paulosouza.net
    E-mail: paulorpereirasouza@hotmail.com. twitter facebook linkedin
    segunda-feira, 9 de maio de 2011 20:36
  • Júnior,

    A melhor maneira para implementar uma autenticação customizada no MVC é usando uma ActionFilterAttribute em conjunto com a "decoration" dos controllers.

    Segue abaixo um exemplo:

    Arquivo 1: Classe que implementa o ActionFilter

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Security;
    
    namespace xxxxxxxxxxx
    {
      public class RequiresAuthenticationAttribute : ActionFilterAttribute
      {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
          //redirect if not authenticated
          if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
          {
            //use the current url for the redirect
            string redirectOnSuccess = filterContext.HttpContext.Request.Url.AbsolutePath;
    
            //send them off to the login page
            string redirectUrl = string.Format("?ReturnUrl={0}", redirectOnSuccess);
            string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
            filterContext.HttpContext.Response.Redirect(loginUrl, true);
          }
        }
      }
    }
    
    Classe 2: Implementar a ActionFilter para as roles (permissões)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Security;
    
    namespace xxxxxxxxxxxxxxx
    {
      public class RequireRolesAttribute : ActionFilterAttribute
      {
        public string RoleToCheckFor { get; set; }
    
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
          //redirect if the user is not authenticated
          if (!String.IsNullOrEmpty(RoleToCheckFor))
          {
            if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
              //use the current url for the redirect
              string redirectOnSuccess = filterContext.HttpContext.Request.Url.AbsolutePath;
    
              //send them off to the login page
              string redirectUrl = string.Format("?ReturnUrl={0}", redirectOnSuccess);
              string loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
              filterContext.HttpContext.Response.Redirect(loginUrl, true);
            }
            else
            {
              FormsIdentity identity = (FormsIdentity)filterContext.HttpContext.User.Identity;
              FormsAuthenticationTicket ticket = identity.Ticket;
    
              string actualRole = ticket.UserData;
    
              //bool isAuthorized = actualRole == this.RoleToCheckFor ? true : false;// filterContext.HttpContext.User.IsInRole(this.RoleToCheckFor);
              bool isAuthorized = false;
    
              string[] roles = RoleToCheckFor.Split(',');
    
              for (int i = 0; i < roles.Length; i++)
              {
                if(filterContext.HttpContext.User.IsInRole(this.RoleToCheckFor))
                  isAuthorized = true;
              }
    
              if (!isAuthorized)
                throw new UnauthorizedAccessException("Você não está autorizado a acessar esta página!");
            }
          }
          else
          {
            throw new InvalidOperationException("No Role Specified");
          }
        }
      }
    }
    

    3: View que recebe os dados de login e autentica o usuário:

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult LogOn(string userName, string password)
        {
          //A AUTENTICAÇÃO ESTÁ EM UMA CAMADA SEPARADA
          USUARIOS usu = _service.AutenticaUsuario(userName, password);
          if (usu != null)
          {
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(30), false, usu.PERFIL.NOMECODIGO, FormsAuthentication.FormsCookiePath);
    
            //For security reasons we may hash the cookies
            string hashCookies = FormsAuthentication.Encrypt(ticket);
            HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashCookies);
    
            // add the cookie to user browser
            Response.Cookies.Add(cookie);
    
            return RedirectToAction("Index", "Home");
          }
          return View();
        }
    

    4: Decore os seus controllers (global):

      [RequiresAuthentication]
      [RequireRoles(RoleToCheckFor = "master")]
      public class ControleController : Controller
      {
       //...
      }
    

    4.1: Ou decore uma view específica:

      public class SegmentoController : Controller
      {
        //
        // GET: /Segmento/
        [RequiresAuthentication]
        [RequireRoles(RoleToCheckFor = "master,secretaria")]
        public ActionResult Index()
        {
          return View(_service.ListSegmentos());
        }
      }
    
    Usando esta técnica fica fácil usar suas próprias tabelas sem ter que usar o membership.

     

     

     

     

    terça-feira, 10 de maio de 2011 05:08
    Moderador
  • João esses filtros eu coloco na pasta models ou crio uma pasta para os filtros e outra estou usando entity framework e mvc 3 tem alguma diferença ? como eu altero no mvc 3 a view login para uma view que eu crie
    Junior
    terça-feira, 10 de maio de 2011 11:25
  • João, Junior,

    Concordo que criar uma implemetação de ActionFilterAttribute é a forma mais adequada de intervir na requisição no MVC. Agora no seu exemplo você utiliza filterContext.HttpContext.User.IsInRole(this.RoleToCheckFor)), se você não possui um RoleProvider neste caso como ele irá lidar com essa instrução?

    Possua uma implementação de MembershipProvider, RoleProvider, mas como na maioria dos cenários preciso de algo mais flexivel, criei um Extension Method string HasPermission(this IPrincipal principal, string permission), onde permissao pode ser qualquer coisa/recurso/regra de negocio dentro do sistema. Como é um método que extende as funcionalidades de HttpContext.User posso utiliza-lo em toda aplicação web páginas/controladores. Para certificar que as requisições que precisam de permissões especiais criei uma implementação de ActionFilterAttribute semelhante a sua mas que apenas faz uma checagem em filterContext.HttpContext.User.HasPermission(permission).

    Dessa forma em situações onde o esquema tradicional de autorização do .NET me atende faço uso de Authorize nas outras faço uso de minha implementação AuthorizePermission.

     


    Atenciosamente, Paulo R. Pereira de Souza
    http://paulosouza.net
    E-mail: paulorpereirasouza@hotmail.com. twitter facebook linkedin
    terça-feira, 10 de maio de 2011 15:08
  • Paulo, como falei anteriormente estou estudando mvc e estou tentando migrar uma página já existente em web forms para mvc, já consegui implementar o membership por esse tutorial

    http://kitsula.com/Article/Custom-Membership-Provider-for-MVC

    Fiz uma adaptação apenas no MembershipProvider(validateuser) para ele ir no meu entity framework e testar se o usuario e senha existem no banco e funcionou perfeito, agora vou ver a implementação do provider.

    Se vc pudesse exemplificar ou dizer um tutorial onde posso ver esse seu exemplo ajudaria bastante.


    Junior
    terça-feira, 10 de maio de 2011 16:04
  • Júnior,

    A pasta onde os arquivos das ActionFilter (classes) ficam não faz muita diferença, o importante é o namespace que deve corresponder ao da sua aplicação.

    Quanto à modificar a view login para utilizar a sua basta apagar todas as Action e inserir as suas.

    No meu caso utilizo assim:

      public class AccountController : Controller
      {
        private Domain _domain;
    
        public HomeController()
        {
          _domain = new Domain();
        }
    
        public ActionResult Index()
        {
          if (User.Identity.IsAuthenticated)
            return RedirectToAction("Index", "Menu");
          else
            return View();
        }
    
        [HttpPost]
        public ActionResult Index([Bind(Exclude = "Id")]User user)
        {
          if (ModelState.IsValid)
          {
            if (_domain.ValidateUser(user.Login, user.Password))
            {
              FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, "Administrador", DateTime.Now, DateTime.Now.AddMinutes(30), false, "admin", FormsAuthentication.FormsCookiePath);
    
              //For security reasons we may hash the cookies
              string hashCookies = FormsAuthentication.Encrypt(ticket);
              HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashCookies);
    
              // add the cookie to user browser
              Response.Cookies.Add(cookie);
    
              return RedirectToAction("Index", "Menu");
    
            }
            else
            {
              ModelState.AddModelError("login", "Dados de login incorretos!");
              return View();
            }
          }
          else
          {
            return View();
          }
        }
    }
    

    • Marcado como Resposta Junior_luiz quarta-feira, 11 de maio de 2011 11:45
    terça-feira, 10 de maio de 2011 17:21
    Moderador
  • Sim você basicamente vai precisar implementar apenas oum método no role provider.

    Ok, dessa forma você conseguirá utilizar o Atributo Authorize do MVC com o seu esquema customizado, caso precise de algo mais personalizado você pode pensar a respeito do que falei no ultimo post.

    Um exemplo de implementação de GetRolesForUser seria:

    public override string[] GetRolesForUser(string username)
            {
               
    	  IUserDao userDao = DaoFactory.GetUserDao();
     
                User user = userDao.GetUserByLogin(username);
     
                var roles = user.Roles.Select(r => r.Name).ToArray();
                return roles;
            }

    Atenciosamente, Paulo R. Pereira de Souza
    http://paulosouza.net
    E-mail: paulorpereirasouza@hotmail.com. twitter facebook linkedin
    terça-feira, 10 de maio de 2011 17:44
  • Paulo tenho 3 tabelas : usuario,permissao e usuariopermissao,estou tentando assim no GetUsersInRole e no GetRolesForUsers mais está dando erro dizendo que o roles está vazio ou seja o linq não trás nada

    public override string[] GetRolesForUser(string username)
        {
          using (MembershipEntities db = new MembershipEntities())
          {
            usuario user = db.usuarios.FirstOrDefault(u => u.Nome.Equals(username, StringComparison.CurrentCultureIgnoreCase));
                     
            var roles = from p in user.permissaos 
                  from r in db.permissaos 
                  where p.idpermissao == r.idpermissao 
                  select r.descricao;
    
            if (roles != null)
              return roles.ToArray();
            else
              return new string[] { };
            ;
          } 
        }
    

    Junior
    terça-feira, 10 de maio de 2011 18:28
  • Junior,

    Mudei o exemplo anterior para ficar mais simples. Me diz uma coisa, por que você fez a query dessa forma? Você não podeira fazer assim:

    user.permissaos.Select(p => p.descricao).ToArray();

    Uma pergunta, o que permissão significa no seu sistema? Significa um Role (Papél do Usuário) ou outra coisa?


    Atenciosamente, Paulo R. Pereira de Souza
    http://paulosouza.net
    E-mail: paulorpereirasouza@hotmail.com. twitter facebook linkedin
    terça-feira, 10 de maio de 2011 19:03
  • permissao é como um grupo onde um usuario pode pertencer a varios grupos, Paulo mudei a lógica e não dá mais erro na entrada mais depois de logado que tento acessar uma pagina que tem permissao ele dá erro aqui

     usuario user = db.usuarios.FirstOrDefault(u => u.Nome.Equals(username, StringComparison.CurrentCultureIgnoreCase));

    Mais passa no login

     


    Junior
    terça-feira, 10 de maio de 2011 19:06
  • Qual o erro?
    Atenciosamente, Paulo R. Pereira de Souza
    http://paulosouza.net
    E-mail: paulorpereirasouza@hotmail.com. twitter facebook linkedin
    terça-feira, 10 de maio de 2011 19:43
  • qdo ele executa o linq user está vazio,

    olhei o seu exemplo me diz uma coisa, como vc implementou o getUserByLogin  o que vc trás no return dele, estou tentando fazer aqui mais não sei o return dele, tentei true não aceita, fiz assim.

    public override MembershipUser GetUserByLogin(string username)
        {
          using (MembershipEntities db = new MembershipEntities())
          {
            var result = from u in db.usuarios where (u.Nome == username) select u;
          }
          return true;
        }
    

     

    vc fez isso no seu exemplo

    User user = userDao.GetUserByLogin(username);


    Junior
    terça-feira, 10 de maio de 2011 19:55
  • Ok, entendi o que você está fazendo. Como você pode ver não utilizo o MembershipProvider para buscar o usuário dentro do método RoleProvider.GetRolesForUsers, tenho uma camada de acesso a dados que retorna o usuário. No seu método GetRolesForUsers utilize um objeto de acesso a dados ou faça:

    db.usuarios.FirstOrDefault(u => u.Nome = username) que retorna seu usuário (db.usuarios).

     


    Atenciosamente, Paulo R. Pereira de Souza
    http://paulosouza.net
    E-mail: paulorpereirasouza@hotmail.com. twitter facebook linkedin
    • Marcado como Resposta Junior_luiz quarta-feira, 11 de maio de 2011 11:44
    terça-feira, 10 de maio de 2011 20:09
  • Paulo deu certo não só colocando simplesmente isso mais fiz assim e deu certo

    public override string[] GetRolesForUser(string username)
        {
          using (MembershipEntities db = new MembershipEntities())
          {
            if (HttpContext.Current.User != null)
            {
              usuario user = db.usuarios.FirstOrDefault(u => u.Login == username);
              var roles = user.permissaos.Select(r => r.descricao).ToArray();
              return roles;
            }
            else
            {
              usuario user = db.usuarios.FirstOrDefault(u => u.Nome.Equals(username, StringComparison.CurrentCultureIgnoreCase));
              var roles = user.permissaos.Select(r => r.descricao).ToArray();
              return roles;
            }
            
          } 
        }
    
    Muito obrigado pela ajuda
    Junior
    quarta-feira, 11 de maio de 2011 11:40