none
Exibindo links conforme Roles do usuario RRS feed

  • Pergunta

  • Boa noite galera! 

    Estava estudando ASP.NET MVC4 e fazendo um projetinho apenas para estudos(famoso projetinho "copa do mundo"),

    configurei as Roles e tal, coloquei as anotações nos controllers como deve ser.

    Situacao

    o controle de acesso nos controladores esta funcionando perfeitamente, porem imaginamos que eu queira usar para administradores e outros usuarios uma mesma view que lista Jogadores, obviamente os administradores podem fazer o CRUD nos registros desta lista, mas os usuarios que possuem limitaçao devem somente ver os jogadores, sem poder fazer nada alem disso

    as anotacoes funcionam perfeitamente impedindo nao administradores de alterar,deletar,incluir jogadores, porem para ficar algo mais bem feito, gostaria de exibir os links somente para quem vai realmente usa-los, ou seja, controlar links para acoes atraves das Roles

    Antes de pesquisar resolvi fazer um Helper para isso com objetivo de praticar tendo em vista que estou iniciando nesta tecnologia

    Solução

    resolvi entao criar um helper para gerar esses links levando em consideracao as roles do usuario.. segue abaixo o metodo do helper "ActionLinkPerRole"

            public static MvcHtmlString ActionLinkPerRole(this HtmlHelper helper, LinkModel link, WebViewPage currentUser)
            {
                string htmlComplete = "";
                
                //verifica se o link é permitido para a role do usuario atual
                if (link.IsValidRole(currentUser))
                {
                    //se for permitido entao pega o html
                    htmlComplete = link.GetHtmlLink();
                }
                
                return new MvcHtmlString(htmlComplete);
            }

    observe que alem do parametro helper tambem passo um parametro do tipo LinkModel e outro do tipo WebViewPage 

    LinkModel = classe criada para guardar um modelo de link que utilizarei para gerar os links que estarao presentes na view, possui dois metodos basicos responsaveis por verificar se o link esta liberado para a role do usuario atual e gerar o html completo do link.

    Veja a classe abaixo

    Obs: basicamente a classe funciona criando um objeto LinkModel através do construtor onde serao passados parametros necessarios para montar o link,estilizar o link e tambem um array com as roles para quais este link será visivel, baseado nisso o html é gerado ou nao pelo metodo GetHtmlLink

    public class LinkModel
        {
            //classe css do link e a div que circula
            public string divClassCss;
            public string linkClassCss;
    
            //informacoes da rota no navegador
            public string linkControllerName;
            public string linkActionName;
            public int? linkId;
    
            //texto do link visivel para o usuario
            public string linkText;
    
            //lista de roles 
            public string[] listRoles;
    
            //construtor contendo todos os parametros necessarios
            public LinkModel(string LinkText,string LinkActionName,string LinkControllerName,int LinkId,string DivClassCss,string LinkClassCss,string[] ListRoles)
            {
                this.divClassCss = DivClassCss;
                this.linkClassCss = LinkClassCss;
                this.linkControllerName = LinkControllerName;
                this.linkActionName = LinkActionName;
                this.linkId = LinkId;
                this.linkText = LinkText;
                this.listRoles = ListRoles;
    
            }
    
            public bool IsValidRole(WebViewPage currentUser)
            {
                bool encontrou = false;
    
                //percorre as roles permitidas para este link
                for (int i = 0; i < this.listRoles.Length; i++)
                {   
                    //verifica se encontra dentro das roles deste link.. a role do usuario atual para fazer a liberacao, caso contrario nao libera
                    if(currentUser.User.IsInRole(this.listRoles[i])){
                        encontrou = true;
                    }
                }
    
                return encontrou;
            }
    
            public string GetHtmlLink()
            {
                // Monta o link completo baseado nas propriedades do objeto 'LinkModel' instanciado
    
                string link;
                string rotaDoLink;
                string htmlComplete;
    
                //monta a rota do link..
                rotaDoLink = this.linkId.HasValue
                    ? String.Format("/{0}/{1}/{2}", this.linkControllerName, this.linkActionName, this.linkId)
                    : String.Format("/{0}/{1}", this.linkControllerName, this.linkActionName);
    
                //agora monta o restante do link
                link = this.linkClassCss != ""
                    ? String.Format("<a class='{0}' href='{1}'>{2}</a>", this.linkClassCss, rotaDoLink, this.linkText)
                    : String.Format("<a href='{0}'>{1}</a>", rotaDoLink, this.linkText);
                
                //insere o link dentro de uma div caso tenha sido passada uma classe para a div no construtor
                htmlComplete = this.divClassCss != ""
                    ? String.Format("<div class='{0}'>{1}</div>", this.divClassCss, link)
                    : link;
    
                return htmlComplete;
            }
        }

    Tendo criado o helper ActionLinkPerRole e a classe LinkModel, basta no controlador desejado, criar um ou varios objetos do tipo LinkModel e passa-los pela ViewBag, resgatando depois na View e passando por parametro este LinkModel junto com a WebViewPage da view corrente para o helper como no exemplo abaixo.

    LinkModel linkmodel = (LinkModel)ViewBag.Meulink;

    @Html.ActionLinkPerRole(linkmodel,this)

    this - dentro da view pasa o objeto WebViewPage corrente da view

    Resumindo: Foi desta forma que encontrei uma forma de controlar meus links levando as roles em consideracao

    e separando o maximo possivel a lógica da view, mantendo o controlador responsavel por gerar o conteudo, li sobre usar um if

    para gerar ou nao os links que é bem pratico, mas a meu ver é limitado se a intensao for fazer algo mais robusto

    Li tambem sobre usar partial views para os diferentes tipos de roles e também sobre duplicar as views para exibir

    conforme a role do usuario, o que eu considero um exagero duplicar uma view por 2 ou 3 links..

    A questao é, dada a situacao, como vcs fariam?.. opinioes, dicas etc

    aguardo respostas, da trabalho pra caramba digitar isso td shauhaushau... boa noite !!!

        

     


    terça-feira, 2 de abril de 2013 03:15

Todas as Respostas

  • Olha cara, eu acredito que nesse tipo de situação, não existe forma certa ou errada de se fazer... Você fez um helper, que resolve seu problema. Helpers são interessantes, pois são bem discretos e deixam o código mais bonito, então acho que está valendo.

    Quando eu faço esse tipo de situação, eu crio várias partial views, e faço um if na própia view, ou faço um helper pra saber qual partial view irei implementar... Dessa forma eu acho mais fácil, porque caso tenha que mudar alguma coisa, eu mudo direto a view, aí fica uma manutenção mais fácil.


    Ao infinito e além!

    terça-feira, 2 de abril de 2013 12:07
  • Entendo... como voce falou tem varias maneiras, por isso gostaria de  trocar ideias sobre isso, e saber da opiniao da galera como é feito... ou talvez um link mostrando opçoes de padroes para isso...

    ainda estou adaptando o helper para ficar mais funcional, criei ontem apenas para controlar os links em uma view para diferentes tipos de usuarios. na view fica interessante pq para inserir os links utilizo um trecho de codigo para resgatar o LinkModel da ViewBag e dai pra frente é só usar o helper passando os parametros...

    @{ LinkModel LinkCadastrar = (LinkModel)ViewBag.linkCadastrar; LinkModel LinkDeletar = (LinkModel)ViewBag.linkDeletar; } @Html.ActionLinkPerRole(LinkCadastrar, this)

    @Html.ActionLinkPerRole(LinkDeletar,this,model.Id)

    - adaptei um parametro "Id" na chamada do Helper, antes estava passando o Id no construtor mas não estava correto, agora no caso de precisar de um Id para o actionLink, posso passa-lo por parametro

    - fiquei na duvida quanto ao desempenho por envolver mais objetos na ViewBag  e passar a WebViewPage  para ser acessada dentro do helper 

    terça-feira, 2 de abril de 2013 12:26