Atribuir funções aos usuários (C#)

por Scott Mitchell

Observação

Desde que este artigo foi escrito, os provedores de associação de ASP.NET foram substituídos por ASP.NET Identity. É altamente recomendável atualizar aplicativos para usar a plataforma ASP.NET Identity em vez dos provedores de associação apresentados no momento em que este artigo foi escrito. ASP.NET Identity tem várias vantagens sobre o sistema de associação ASP.NET, incluindo :

  • Melhor desempenho
  • Extensibilidade e testabilidade aprimoradas
  • Suporte para OAuth, OpenID Connect e autenticação de dois fatores
  • Suporte à identidade baseada em declarações
  • Melhor interoperabilidade com ASP.Net Core

Baixar código ou baixar PDF

Neste tutorial, criaremos duas páginas ASP.NET para ajudar a gerenciar quais usuários pertencem a quais funções. A primeira página incluirá recursos para ver quais usuários pertencem a uma determinada função, a quais funções um determinado usuário pertence e a capacidade de atribuir ou remover um usuário específico de uma função específica. Na segunda página, aumentaremos o controle CreateUserWizard para que ele inclua uma etapa para especificar a quais funções o usuário recém-criado pertence. Isso é útil em cenários em que um administrador é capaz de criar novas contas de usuário.

Introdução

O tutorial anterior examinou a estrutura Funções e o SqlRoleProvider; vimos como usar a Roles classe para criar, recuperar e excluir funções. Além de criar e excluir funções, precisamos ser capazes de atribuir ou remover usuários de uma função. Infelizmente, ASP.NET não envia nenhum controle da Web para gerenciar quais usuários pertencem a quais funções. Em vez disso, devemos criar nossas próprias páginas ASP.NET para gerenciar essas associações. A boa notícia é que adicionar e remover usuários para funções é muito fácil. A Roles classe contém vários métodos para adicionar um ou mais usuários a uma ou mais funções.

Neste tutorial, criaremos duas páginas ASP.NET para ajudar a gerenciar quais usuários pertencem a quais funções. A primeira página incluirá recursos para ver quais usuários pertencem a uma determinada função, a quais funções um determinado usuário pertence e a capacidade de atribuir ou remover um usuário específico de uma função específica. Na segunda página, aumentaremos o controle CreateUserWizard para que ele inclua uma etapa para especificar a quais funções o usuário recém-criado pertence. Isso é útil em cenários em que um administrador é capaz de criar novas contas de usuário.

Vamos começar!

Listando quais usuários pertencem a quais funções

A primeira ordem de negócios para este tutorial é criar uma página da Web da qual os usuários podem ser atribuídos a funções. Antes de nos preocuparmos com como atribuir usuários a funções, vamos primeiro nos concentrar em como determinar quais usuários pertencem a quais funções. Há duas maneiras de exibir essas informações: "por função" ou "por usuário". Poderíamos permitir que o visitante selecionasse uma função e mostrasse todos os usuários que pertencem à função (a exibição "por função") ou poderíamos solicitar que o visitante selecionasse um usuário e mostrasse as funções atribuídas a esse usuário (a exibição "por usuário").

A exibição "por função" é útil em circunstâncias em que o visitante deseja conhecer o conjunto de usuários que pertencem a uma função específica; a exibição "por usuário" é ideal quando o visitante precisa conhecer as funções de um usuário específico. Vamos fazer com que nossa página inclua interfaces "por função" e "por usuário".

Começaremos com a criação da interface "por usuário". Essa interface consistirá em uma lista suspensa e uma lista de caixas de seleção. A lista suspensa será preenchida com o conjunto de usuários no sistema; as caixas de seleção enumerarão as funções. Selecionar um usuário na lista suspensa marcar essas funções às quais o usuário pertence. A pessoa que visita a página pode marcar ou desmarcar as caixas de seleção para adicionar ou remover o usuário selecionado das funções correspondentes.

Observação

Usar uma lista suspensa para listar as contas de usuário não é uma opção ideal para sites em que pode haver centenas de contas de usuário. Uma lista suspensa foi projetada para permitir que um usuário escolha um item de uma lista relativamente curta de opções. Ele se torna rapidamente desordado à medida que o número de itens de lista aumenta. Se você estiver criando um site que terá um número potencialmente grande de contas de usuário, convém considerar o uso de uma interface de usuário alternativa, como um GridView paginável ou uma interface filtrolável que lista solicita que o visitante escolha uma letra e, em seguida, mostre apenas os usuários cujo nome de usuário começa com a letra selecionada.

Etapa 1: Criando a interface do usuário "por usuário"

Abra a UsersAndRoles.aspx página. Na parte superior da página, adicione um controle Web label chamado ActionStatus e desmarque sua Text propriedade. Usaremos esse Rótulo para fornecer comentários sobre as ações executadas, exibindo mensagens como "O Tito do Usuário foi adicionado à função Administradores" ou "O Jisun do Usuário foi removido da função Supervisores". Para que essas mensagens se destaquem, defina a propriedade do CssClass Rótulo como "Importante".

<p align="center"> 

     <asp:Label ID="ActionStatus" runat="server" CssClass="Important"></asp:Label> 
</p>

Em seguida, adicione a seguinte definição de classe CSS à Styles.css folha de estilos:

.Important 
{ 
     font-size: large; 
     color: Red; 
}

Essa definição de CSS instrui o navegador a exibir o Rótulo usando uma fonte grande e vermelha. A Figura 1 mostra esse efeito por meio da Designer do Visual Studio.

A propriedade CssClass do rótulo resulta em uma fonte grande e vermelha

Figura 1: a propriedade do CssClass rótulo resulta em uma fonte grande e vermelha (clique para exibir a imagem em tamanho real)

Em seguida, adicione um DropDownList à página, defina sua ID propriedade como UserListe defina sua AutoPostBack propriedade como True. Usaremos esse DropDownList para listar todos os usuários do sistema. Este DropDownList será associado a uma coleção de objetos MembershipUser. Como queremos que o DropDownList exiba a propriedade UserName do objeto MembershipUser (e use-o como o valor dos itens de lista), defina as propriedades e DataValueField do DataTextField DropDownList como "UserName".

Abaixo do DropDownList, adicione um Repetidor chamado UsersRoleList. Esse Repetidor listará todas as funções no sistema como uma série de caixas de seleção. Defina o repeater usando ItemTemplate a seguinte marcação declarativa:

<asp:Repeater ID="UsersRoleList" runat="server"> 
     <ItemTemplate> 
          <asp:CheckBox runat="server" ID="RoleCheckBox" AutoPostBack="true" 

               Text='<%# Container.DataItem %>' /> 
          <br /> 
     </ItemTemplate> 
</asp:Repeater>

A ItemTemplate marcação inclui um único controle Web CheckBox chamado RoleCheckBox. A propriedade checkbox AutoPostBack é definida como True e a Text propriedade está associada a Container.DataItem. O motivo pelo qual a sintaxe de vinculação de dados é simplesmente Container.DataItem é porque a estrutura Funções retorna a lista de nomes de função como uma matriz de cadeia de caracteres e é essa matriz de cadeia de caracteres que associaremos ao Repetidor. Uma descrição completa de por que essa sintaxe é usada para exibir o conteúdo de uma matriz associada a um controle da Web de dados está além do escopo deste tutorial. Para obter mais informações sobre esse assunto, consulte Associando uma matriz escalar a um controle da Web de dados.

Neste ponto, a marcação declarativa da interface "por usuário" deve ser semelhante à seguinte:

<h3>Manage Roles By User</h3> 

<p> 
     <b>Select a User:</b> 
     <asp:DropDownList ID="UserList" runat="server" AutoPostBack="True" 
          DataTextField="UserName" DataValueField="UserName"> 

     </asp:DropDownList> 
</p> 
<p> 
     <asp:Repeater ID="UsersRoleList" runat="server"> 
          <ItemTemplate> 
               <asp:CheckBox runat="server" ID="RoleCheckBox" AutoPostBack="true" 

                    Text='<%# Container.DataItem %>' /> 
               <br /> 
          </ItemTemplate> 
     </asp:Repeater> 
</p>

Agora estamos prontos para gravar o código para associar o conjunto de contas de usuário ao DropDownList e ao conjunto de funções ao Repetidor. Na classe code-behind da página, adicione um método chamado BindUsersToUserList e outro chamado BindRolesList, usando o seguinte código:

private void BindUsersToUserList() 
{ 
     // Get all of the user accounts 
     MembershipUserCollection users = Membership.GetAllUsers(); 
     UserList.DataSource = users; 
     UserList.DataBind(); 
}
 
private void BindRolesToList() 
{ 
     // Get all of the roles 
     string[] roles = Roles.GetAllRoles(); 
     UsersRoleList.DataSource = roles; 
     UsersRoleList.DataBind(); 
}

O BindUsersToUserList método recupera todas as contas de usuário no sistema por meio do Membership.GetAllUsers método . Isso retorna um MembershipUserCollection objeto , que é uma coleção de MembershipUser instâncias. Essa coleção é associada ao UserList DropDownList. As MembershipUser instâncias que compõem a coleção contêm uma variedade de propriedades, como UserName, Email, CreationDatee IsOnline. Para instruir o DropDownList a exibir o valor da UserName propriedade , verifique se as UserList propriedades e DataValueField do DataTextField DropDownList foram definidas como "UserName".

Observação

O Membership.GetAllUsers método tem duas sobrecargas: uma que não aceita parâmetros de entrada e retorna todos os usuários e outra que recebe valores inteiros para o índice de página e o tamanho da página e retorna apenas o subconjunto especificado dos usuários. Quando há grandes quantidades de contas de usuário sendo exibidas em um elemento de interface do usuário paginável, a segunda sobrecarga pode ser usada para paginar com mais eficiência os usuários, pois retorna apenas o subconjunto preciso das contas de usuário em vez de todas elas.

O BindRolesToList método começa chamando o Roles método da GetAllRolesclasse , que retorna uma matriz de cadeia de caracteres que contém as funções no sistema. Essa matriz de cadeia de caracteres é associada ao Repetidor.

Por fim, precisamos chamar esses dois métodos quando a página for carregada pela primeira vez. Adicione o seguinte código ao manipulador de eventos do Page_Load:

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 
          // Bind the users and roles 
          BindUsersToUserList(); 
          BindRolesToList(); 
     } 
}

Com esse código em vigor, reserve um momento para visitar a página por meio de um navegador; sua tela deve ser semelhante à Figura 2. Todas as contas de usuário são preenchidas na lista suspensa e, abaixo disso, cada função aparece como uma caixa de seleção. Como definimos as AutoPostBack propriedades de DropDownList e CheckBoxes como True, alterar o usuário selecionado ou verificar ou desmarcar uma função causa um postback. Nenhuma ação é executada, no entanto, porque ainda não escrevemos código para lidar com essas ações. Abordaremos essas tarefas nas próximas duas seções.

A página exibe os usuários e as funções

Figura 2: a página exibe os usuários e as funções (clique para exibir a imagem em tamanho real)

Verificando as funções às quais o usuário selecionado pertence

Quando a página é carregada pela primeira vez ou sempre que o visitante seleciona um novo usuário na lista suspensa, precisamos atualizar as UsersRoleListcaixas de seleção para que uma determinada caixa de seleção de função seja marcada somente se o usuário selecionado pertencer a essa função. Para fazer isso, crie um método chamado CheckRolesForSelectedUser com o seguinte código:

private void CheckRolesForSelectedUser() 
{ 
     // Determine what roles the selected user belongs to 
     string selectedUserName = UserList.SelectedValue; 
     string[] selectedUsersRoles = Roles.GetRolesForUser(selectedUserName); 

     // Loop through the Repeater's Items and check or uncheck the checkbox as needed 

     foreach (RepeaterItem ri in UsersRoleList.Items) 
     { 
          // Programmatically reference the CheckBox 
          CheckBox RoleCheckBox = ri.FindControl("RoleCheckBox") as CheckBox; 
          // See if RoleCheckBox.Text is in selectedUsersRoles 
          if (selectedUsersRoles.Contains<string>(RoleCheckBox.Text)) 
               RoleCheckBox.Checked = true; 
          else 
               RoleCheckBox.Checked = false; 
     } 
}

O código acima começa determinando quem é o usuário selecionado. Em seguida, ele usa o método da GetRolesForUser(userName) classe Roles para retornar o conjunto de funções do usuário especificado como uma matriz de cadeia de caracteres. Em seguida, os itens do Repetidor são enumerados e a CheckBox de RoleCheckBox cada item é referenciada programaticamente. A Caixa de Seleção será marcada somente se a função à qual ela corresponde estiver contida na matriz de selectedUsersRoles cadeia de caracteres.

Observação

A selectedUserRoles.Contains<string>(...) sintaxe não será compilada se você estiver usando ASP.NET versão 2.0. O Contains<string> método faz parte da biblioteca LINQ, que é nova no ASP.NET 3.5. Se você ainda estiver usando ASP.NET versão 2.0, use o Array.IndexOf<string> método .

O CheckRolesForSelectedUser método precisa ser chamado em dois casos: quando a página é carregada pela primeira vez e sempre que o UserList índice selecionado do DropDownList é alterado. Portanto, chame esse método do Page_Load manipulador de eventos (após as chamadas para BindUsersToUserList e BindRolesToList). Além disso, crie um manipulador de eventos para o evento dropDownList SelectedIndexChanged e chame esse método de lá.

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 

          // Bind the users and roles 
          BindUsersToUserList(); 
          BindRolesToList(); 
          // Check the selected user's roles 
          CheckRolesForSelectedUser(); 
     } 
} 

... 

protected void UserList_SelectedIndexChanged(object sender, EventArgs e) 
{ 
     CheckRolesForSelectedUser(); 
}

Com esse código em vigor, você pode testar a página por meio do navegador. No entanto, como a UsersAndRoles.aspx página atualmente não tem a capacidade de atribuir usuários a funções, nenhum usuário tem funções. Criaremos a interface para atribuir usuários a funções em um momento, para que você possa usar minha palavra de que esse código funciona e verificar se ele funciona mais tarde ou você pode adicionar manualmente usuários a funções inserindo registros aspnet_UsersInRoles na tabela para testar essa funcionalidade agora.

Atribuindo e removendo usuários de funções

Quando o visitante verifica ou desmarca uma CheckBox no UsersRoleList Repetidor, precisamos adicionar ou remover o usuário selecionado da função correspondente. No momento, a propriedade checkBox AutoPostBack está definida como True, o que causa um postback sempre que uma CheckBox no Repetidor é marcada ou desmarcada. Em suma, precisamos criar um manipulador de eventos para o evento checkbox CheckChanged . Como CheckBox está em um controle Repeater, precisamos adicionar manualmente o encanamento do manipulador de eventos. Comece adicionando o manipulador de eventos à classe code-behind como um protected método, da seguinte forma:

protected void RoleCheckBox_CheckChanged(object sender, EventArgs e) 
{ 

}

Retornaremos para escrever o código para esse manipulador de eventos em um momento. Mas primeiro vamos concluir o encanamento de manipulação de eventos. Na Caixa de Seleção no do ItemTemplateRepetidor, adicione OnCheckedChanged="RoleCheckBox_CheckChanged". Essa sintaxe conecta o RoleCheckBox_CheckChanged manipulador de eventos ao RoleCheckBoxevento do .CheckedChanged

<asp:CheckBox runat="server" ID="RoleCheckBox" 
     AutoPostBack="true" 
     Text='<%# Container.DataItem %>' 
     OnCheckedChanged="RoleCheckBox_CheckChanged" />

Nossa tarefa final é concluir o manipulador de RoleCheckBox_CheckChanged eventos. Precisamos começar referenciando o controle CheckBox que gerou o evento porque essa instância checkBox nos informa qual função foi marcada ou desmarcada por meio de suas Text propriedades e Checked . Usando essas informações junto com o UserName do usuário selecionado, adicionamos ou removemos o usuário da função por meio do Roles método ou RemoveUserFromRoleda AddUserToRole classe.

protected void RoleCheckBox_CheckChanged(object sender, EventArgs e) 
{ 
     // Reference the CheckBox that raised this event 
     CheckBox RoleCheckBox = sender as CheckBox; 

     // Get the currently selected user and role 
     string selectedUserName = UserList.SelectedValue; 

     string roleName = RoleCheckBox.Text; 

     // Determine if we need to add or remove the user from this role 
     if (RoleCheckBox.Checked) 
     { 
          // Add the user to the role 
          Roles.AddUserToRole(selectedUserName, roleName); 
          // Display a status message 
          ActionStatus.Text = string.Format("User {0} was added to role {1}.", selectedUserName, roleName); 
     } 
     else 
     { 
          // Remove the user from the role 
          Roles.RemoveUserFromRole(selectedUserName, roleName); 
          // Display a status message 
          ActionStatus.Text = string.Format("User {0} was removed from role {1}.", selectedUserName, roleName); 

     } 
}

O código acima começa referenciando programaticamente o CheckBox que gerou o evento, que está disponível por meio do sender parâmetro de entrada. Se a CheckBox estiver marcada, o usuário selecionado será adicionado à função especificada, caso contrário, ele será removido da função. Em ambos os casos, o ActionStatus Rótulo exibe uma mensagem resumindo a ação que acabou de ser executada.

Reserve um momento para testar esta página por meio de um navegador. Selecione o usuário Tito e, em seguida, adicione Tito às funções Administradores e Supervisores.

Tito foi adicionado às funções administradores e supervisores

Figura 3: Tito foi adicionado às funções administradores e supervisores (clique para exibir a imagem em tamanho real)

Em seguida, selecione o usuário Bruce na lista suspensa. Há um postback e as CheckBoxes do Repeater são atualizadas por meio do CheckRolesForSelectedUser. Como Bruce ainda não pertence a nenhuma função, as duas caixas de seleção estão desmarcadas. Em seguida, adicione Bruce à função Supervisores.

Bruce foi adicionado à função supervisores

Figura 4: Bruce foi adicionado à função Supervisores (clique para exibir a imagem em tamanho real)

Para verificar ainda mais a funcionalidade do CheckRolesForSelectedUser método, selecione um usuário diferente de Tito ou Bruce. Observe como as caixas de seleção são desmarcadas automaticamente, indicando que elas não pertencem a nenhuma função. Volte para Tito. As caixas de seleção Administradores e Supervisores devem ser marcadas.

Etapa 2: criando a interface do usuário "Por funções"

Neste ponto, concluímos a interface "por usuários" e estamos prontos para começar a lidar com a interface "por funções". A interface "por funções" solicita que o usuário selecione uma função em uma lista suspensa e, em seguida, exibe o conjunto de usuários que pertencem a essa função em um GridView.

Adicione outro controle DropDownList à UsersAndRoles.aspx página. Coloque este abaixo do controle Repeater, nomeie-o RoleListe defina sua propriedade como AutoPostBack True. Abaixo disso, adicione um GridView e nomeie-o RolesUserListcomo . Este GridView listará os usuários que pertencem à função selecionada. Defina a propriedade gridView AutoGenerateColumns como False, adicione um TemplateField à coleção da Columns grade e defina sua HeaderText propriedade como "Usuários". Defina o TemplateField para ItemTemplate que ele exiba o valor da expressão Container.DataItem de associação de dados na Text propriedade de um Rótulo chamado UserNameLabel.

Depois de adicionar e configurar o GridView, a marcação declarativa da interface "por função" deve ser semelhante à seguinte:

<h3>Manage Users By Role</h3> 
<p> 
     <b>Select a Role:</b> 

     <asp:DropDownList ID="RoleList" runat="server" AutoPostBack="true"></asp:DropDownList> 
</p> 
<p>      <asp:GridView ID="RolesUserList" runat="server" AutoGenerateColumns="false" 

          EmptyDataText="No users belong to this role."> 
          <Columns> 
               <asp:TemplateField HeaderText="Users"> 
                    <ItemTemplate> 
                         <asp:Label runat="server" id="UserNameLabel" 
                              Text='<%# Container.DataItem %>'></asp:Label> 

                    </ItemTemplate> 
               </asp:TemplateField> 
          </Columns> 
     </asp:GridView> </p>

Precisamos preencher o RoleList DropDownList com o conjunto de funções no sistema. Para fazer isso, atualize o BindRolesToList método para que ele associe a matriz de cadeia de caracteres retornada pelo Roles.GetAllRoles método ao RolesList DropDownList (bem como ao UsersRoleList Repeater).

private void BindRolesToList() 
{ 
     // Get all of the roles 

     string[] roles = Roles.GetAllRoles(); 
     UsersRoleList.DataSource = roles; 
     UsersRoleList.DataBind(); 

     RoleList.DataSource = roles; 
     RoleList.DataBind(); 
}

As duas últimas linhas no BindRolesToList método foram adicionadas para associar o conjunto de funções ao RoleList controle DropDownList. A Figura 5 mostra o resultado final quando exibido por meio de um navegador – uma lista suspensa preenchida com as funções do sistema.

As funções são exibidas na lista suspensa RoleList

Figura 5: As funções são exibidas no RoleList DropDownList (clique para exibir a imagem em tamanho real)

Exibindo os usuários que pertencem à função selecionada

Quando a página é carregada pela primeira vez ou quando uma nova função é selecionada no RoleList DropDownList, precisamos exibir a lista de usuários que pertencem a essa função no GridView. Crie um método chamado DisplayUsersBelongingToRole usando o seguinte código:

private void DisplayUsersBelongingToRole() 
{ 
     // Get the selected role 
     string selectedRoleName = RoleList.SelectedValue; 

     // Get the list of usernames that belong to the role 
     string[] usersBelongingToRole = Roles.GetUsersInRole(selectedRoleName); 

     // Bind the list of users to the GridView 
     RolesUserList.DataSource = usersBelongingToRole; 
     RolesUserList.DataBind(); 
}

Esse método começa obtendo a função selecionada do RoleList DropDownList. Em seguida, ele usa o Roles.GetUsersInRole(roleName) método para recuperar uma matriz de cadeia de caracteres dos UserNames dos usuários que pertencem a essa função. Essa matriz é então associada ao RolesUserList GridView.

Esse método precisa ser chamado em duas circunstâncias: quando a página é carregada inicialmente e quando a função selecionada no RoleList DropDownList é alterada. Portanto, atualize o Page_Load manipulador de eventos para que esse método seja invocado após a chamada para CheckRolesForSelectedUser. Em seguida, crie um manipulador de eventos para o RoleListevento do SelectedIndexChanged e chame esse método de lá também.

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 
          // Bind the users and roles 
          BindUsersToUserList(); 
          BindRolesToList(); 

          // Check the selected user's roles 
          CheckRolesForSelectedUser(); 

          // Display those users belonging to the currently selected role 
          DisplayUsersBelongingToRole(); 
     } 
} 

... 

protected void RoleList_SelectedIndexChanged(object sender, EventArgs e) 
{ 
     DisplayUsersBelongingToRole(); 
}

Com esse código em vigor, o RolesUserList GridView deve exibir os usuários que pertencem à função selecionada. Como mostra a Figura 6, a função Supervisores consiste em dois membros: Bruce e Tito.

O GridView lista os usuários que pertencem à função selecionada

Figura 6: O GridView lista os usuários que pertencem à função selecionada (clique para exibir a imagem em tamanho real)

Removendo usuários da função selecionada

Vamos aumentar o RolesUserList GridView para que ele inclua uma coluna de botões "Remover". Clicar no botão "Remover" para um usuário específico o removerá dessa função.

Comece adicionando um campo de botão Excluir ao GridView. Faça com que esse campo apareça como o mais à esquerda arquivado e altere sua DeleteText propriedade de "Delete" (o padrão) para "Remover".

Captura de tela que mostra como adicionar o botão

Figura 7: Adicionar o botão "Remover" ao GridView (clique para exibir a imagem em tamanho real)

Quando o botão "Remover" é clicado, um postback é exibido e o evento do RowDeleting GridView é acionado. Precisamos criar um manipulador de eventos para esse evento e escrever código que remova o usuário da função selecionada. Crie o manipulador de eventos e adicione o seguinte código:

protected void RolesUserList_RowDeleting(object sender, GridViewDeleteEventArgs e) 
{ 
     // Get the selected role 
     string selectedRoleName = RoleList.SelectedValue; 

     // Reference the UserNameLabel 
     Label UserNameLabel = RolesUserList.Rows[e.RowIndex].FindControl("UserNameLabel") as Label; 

     // Remove the user from the role 
     Roles.RemoveUserFromRole(UserNameLabel.Text, selectedRoleName); 

     // Refresh the GridView 
     DisplayUsersBelongingToRole(); 

     // Display a status message 
     ActionStatus.Text = string.Format("User {0} was removed from role {1}.", UserNameLabel.Text, selectedRoleName); 
}

O código começa determinando o nome da função selecionada. Em seguida, ele referencia programaticamente o UserNameLabel controle da linha cujo botão "Remover" foi clicado para determinar o UserName do usuário a ser removido. Em seguida, o usuário é removido da função por meio de uma chamada para o Roles.RemoveUserFromRole método . Em RolesUserList seguida, o GridView é atualizado e uma mensagem é exibida por meio do ActionStatus controle Rótulo.

Observação

O botão "Remover" não requer nenhum tipo de confirmação do usuário antes de remover o usuário da função. Convido você a adicionar algum nível de confirmação do usuário. Uma das maneiras mais fáceis de confirmar uma ação é por meio de uma caixa de diálogo de confirmação do lado do cliente. Para obter mais informações sobre essa técnica, consulte Adicionando Client-Side confirmação ao excluir.

A Figura 8 mostra a página depois que o usuário Tito foi removido do grupo Supervisores.

Infelizmente, Tito não é mais um supervisor

Figura 8: Infelizmente, Tito não é mais um supervisor (clique para exibir a imagem em tamanho real)

Adicionando novos usuários à função selecionada

Além de remover usuários da função selecionada, o visitante desta página também deve ser capaz de adicionar um usuário à função selecionada. A melhor interface para adicionar um usuário à função selecionada depende do número de contas de usuário que você espera ter. Se seu site abrigar apenas algumas dezenas de contas de usuário ou menos, você poderá usar um DropDownList aqui. Se houver milhares de contas de usuário, você desejará incluir uma interface do usuário que permita que o visitante faça uma página pelas contas, pesquise uma conta específica ou filtre as contas de usuário de alguma outra forma.

Para esta página, vamos usar uma interface muito simples que funciona independentemente do número de contas de usuário no sistema. Ou seja, usaremos uma TextBox, solicitando que o visitante digite o nome de usuário do usuário que ela deseja adicionar à função selecionada. Se nenhum usuário com esse nome existir ou se o usuário já for membro da função, exibiremos uma mensagem em ActionStatus Rótulo. Mas se o usuário existir e não for membro da função, vamos adicioná-lo à função e atualizar a grade.

Adicione uma Caixa de Texto e um Botão abaixo do GridView. Defina TextBox como IDUserNameToAddToRole e defina as propriedades e Text do ID Botão como AddUserToRoleButton e "Adicionar Usuário à Função", respectivamente.

<p> 
     <b>UserName:</b> 
     <asp:TextBox ID="UserNameToAddToRole" runat="server"></asp:TextBox> 
     <br /> 
     <asp:Button ID="AddUserToRoleButton" runat="server" Text="Add User to Role" /> 

</p>

Em seguida, crie um Click manipulador de eventos para o AddUserToRoleButton e adicione o seguinte código:

protected void AddUserToRoleButton_Click(object sender, EventArgs e) 
{ 
     // Get the selected role and username 

     string selectedRoleName = RoleList.SelectedValue; 
     string userNameToAddToRole = UserNameToAddToRole.Text; 

     // Make sure that a value was entered 
     if (userNameToAddToRole.Trim().Length == 0) 
     { 
          ActionStatus.Text = "You must enter a username in the textbox."; 
          return; 
     } 

     // Make sure that the user exists in the system 
     MembershipUser userInfo = Membership.GetUser(userNameToAddToRole); 
     if (userInfo == null) 
     { 
          ActionStatus.Text = string.Format("The user {0} does not exist in the system.", userNameToAddToRole); 

          return; 
     } 

     // Make sure that the user doesn't already belong to this role 
     if (Roles.IsUserInRole(userNameToAddToRole, selectedRoleName)) 
     { 
          ActionStatus.Text = string.Format("User {0} already is a member of role {1}.", userNameToAddToRole, selectedRoleName); 
          return; 
     } 

     // If we reach here, we need to add the user to the role 
     Roles.AddUserToRole(userNameToAddToRole, selectedRoleName); 

     // Clear out the TextBox 
     UserNameToAddToRole.Text = string.Empty; 

     // Refresh the GridView 
     DisplayUsersBelongingToRole(); 

     // Display a status message 

     ActionStatus.Text = string.Format("User {0} was added to role {1}.", userNameToAddToRole, selectedRoleName); }

A maioria do código no Click manipulador de eventos executa várias verificações de validação. Ele garante que o visitante forneceu um nome de usuário no UserNameToAddToRole TextBox, que o usuário existe no sistema e que ele ainda não pertence à função selecionada. Se qualquer uma dessas verificações falhar, uma mensagem apropriada será exibida em ActionStatus e o manipulador de eventos será encerrado. Se todas as verificações forem aprovadas, o usuário será adicionado à função por meio do Roles.AddUserToRole método . Depois disso, a propriedade textbox Text é desmarcada, o GridView é atualizado e o ActionStatus Rótulo exibe uma mensagem indicando que o usuário especificado foi adicionado com êxito à função selecionada.

Observação

Para garantir que o usuário especificado ainda não pertença à função selecionada, usamos o Roles.IsUserInRole(userName, roleName) método , que retorna um valor booliano que indica se userName é um membro de roleName. Usaremos esse método novamente no próximo tutorial quando examinarmos a autorização baseada em função.

Visite a página por meio de um navegador e selecione a função Supervisores no RoleList DropDownList. Tente inserir um nome de usuário inválido – você deverá ver uma mensagem explicando que o usuário não existe no sistema.

Não é possível adicionar um usuário inexistente a uma função

Figura 9: Não é possível adicionar um usuário inexistente a uma função (clique para exibir a imagem em tamanho real)

Agora tente adicionar um usuário válido. Vá em frente e adicione novamente Tito à função Supervisores.

Tito é mais uma vez um supervisor!

Figura 10: Tito é mais uma vez um supervisor! (Clique para exibir a imagem em tamanho real)

Etapa 3: atualização cruzada das interfaces "por usuário" e "por função"

A UsersAndRoles.aspx página oferece duas interfaces distintas para gerenciar usuários e funções. Atualmente, essas duas interfaces atuam independentemente umas das outras, portanto, é possível que uma alteração feita em uma interface não seja refletida imediatamente na outra. Por exemplo, imagine que o visitante da página selecione a função Supervisores do RoleList DropDownList, que lista Bruce e Tito como seus membros. Em seguida, o visitante seleciona Tito no UserList DropDownList, que verifica as caixas de seleção Administradores e Supervisores no UsersRoleList Repetidor. Se o visitante desmarcar a função Supervisor do Repetidor, Tito será removido da função Supervisores, mas essa modificação não será refletida na interface "por função". O GridView ainda mostrará Tito como sendo membro da função Supervisores.

Para corrigir isso, precisamos atualizar o GridView sempre que uma função for marcada ou desmarcada do UsersRoleList Repetidor. Da mesma forma, precisamos atualizar o Repetidor sempre que um usuário é removido ou adicionado a uma função da interface "por função".

O Repeater na interface "por usuário" é atualizado chamando o CheckRolesForSelectedUser método . A interface "por função" pode ser modificada no RolesUserList manipulador de eventos do RowDeleting GridView e no AddUserToRoleButton manipulador de eventos do Click Botão. Portanto, precisamos chamar o CheckRolesForSelectedUser método de cada um desses métodos.

protected void RolesUserList_RowDeleting(object sender, GridViewDeleteEventArgs e) 
{ 
     ... Code removed for brevity ... 

     // Refresh the "by user" interface 
     CheckRolesForSelectedUser(); 
} 

protected void AddUserToRoleButton_Click(object sender, EventArgs e) 
{ 
     ... Code removed for brevity ... 


     // Refresh the "by user" interface 
     CheckRolesForSelectedUser(); 
}

Da mesma forma, o GridView na interface "por função" é atualizado chamando o DisplayUsersBelongingToRole método e a interface "por usuário" é modificada por meio do RoleCheckBox_CheckChanged manipulador de eventos. Portanto, precisamos chamar o DisplayUsersBelongingToRole método desse manipulador de eventos.

protected void RoleCheckBox_CheckChanged(object sender, EventArgs e) 
{ 
     ... Code removed for brevity... 

     // Refresh the "by role" interface 
     DisplayUsersBelongingToRole(); 
}

Com essas pequenas alterações de código, as interfaces "por usuário" e "por função" agora são atualizadas corretamente. Para verificar isso, visite a página por meio de um navegador e selecione Tito e Supervisores em UserList e RoleList DropDownLists, respectivamente. Observe que, ao desmarcar a função Supervisores para Tito do Repetidor na interface "por usuário", o Tito é removido automaticamente do GridView na interface "por função". Adicionar o Tito de volta à função Supervisores da interface "por função" verifica automaticamente a caixa de seleção Supervisores na interface "por usuário".

Etapa 4: Personalizando o CreateUserWizard para incluir uma etapa "Especificar funções"

No tutorial Criando Contas de Usuário, vimos como usar o controle Web CreateUserWizard para fornecer uma interface para criar uma nova conta de usuário. O controle CreateUserWizard pode ser usado de duas maneiras:

  • Como um meio para os visitantes criarem sua própria conta de usuário no site e
  • Como um meio para os administradores criarem novas contas

No primeiro caso de uso, um visitante chega ao site e preenche o CreateUserWizard, inserindo suas informações para se registrar no site. No segundo caso, um administrador cria uma nova conta para outra pessoa.

Quando uma conta está sendo criada por um administrador para alguma outra pessoa, pode ser útil permitir que o administrador especifique a quais funções a nova conta de usuário pertence. No tutorial Armazenandoinformações adicionais do usuário, vimos como personalizar o CreateUserWizard adicionando mais WizardSteps. Vamos examinar como adicionar uma etapa adicional ao CreateUserWizard para especificar as funções do novo usuário.

Abra a CreateUserWizardWithRoles.aspx página e adicione um controle CreateUserWizard chamado RegisterUserWithRoles. Defina a propriedade do ContinueDestinationPageUrl controle como "~/Default.aspx". Como a ideia aqui é que um administrador usará esse controle CreateUserWizard para criar novas contas de usuário, defina a propriedade do LoginCreatedUser controle como False. Essa LoginCreatedUser propriedade especifica se o visitante está conectado automaticamente como o usuário que acabou de criar e usa true como padrão. Definimos como False porque quando um administrador cria uma nova conta, queremos mantê-lo conectado como ele mesmo.

Em seguida, selecione "Adicionar/Remover WizardSteps..." da marca inteligente CreateUserWizard e adicione um novo WizardStep, definindo-o IDSpecifyRolesStepcomo . Mova o SpecifyRolesStep WizardStep para que ele venha após a etapa "Inscrever-se para sua nova conta", mas antes da etapa "Concluir". Defina a WizardSteppropriedade de Title como "Especificar Funções", sua StepType propriedade como Stepe sua AllowReturn propriedade como False.

Captura de tela que mostra as propriedades Especificar Funções selecionadas na janela Editor de Coleção de Etapas do Assistente.

Figura 11: Adicionar o "Especificar Funções" WizardStep ao CreateUserWizard (clique para exibir a imagem em tamanho real)

Após essa alteração, a marcação declarativa de CreateUserWizard deve ser semelhante à seguinte:

<asp:CreateUserWizard ID="RegisterUserWithRoles" runat="server" 
     ContinueDestinationPageUrl="~/Default.aspx" LoginCreatedUser="False"> 

     <WizardSteps> 
          <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server"> 
          </asp:CreateUserWizardStep> 
          <asp:WizardStep ID="SpecifyRolesStep" runat="server" StepType="Step" 

               Title="Specify Roles" AllowReturn="False"> 
          </asp:WizardStep> 
          <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server"> 
          </asp:CompleteWizardStep> 
     </WizardSteps> 

</asp:CreateUserWizard>

Em "Especificar Funções", WizardStepadicione uma CheckBoxList chamada RoleList. Essa CheckBoxList listará as funções disponíveis, permitindo que a pessoa que visita a página marcar a quais funções o usuário recém-criado pertence.

Ficamos com duas tarefas de codificação: primeiro devemos preencher CheckBoxList RoleList com as funções no sistema; segundo, precisamos adicionar o usuário criado às funções selecionadas quando o usuário passar da etapa "Especificar Funções" para a etapa "Concluir". Podemos realizar a primeira tarefa no Page_Load manipulador de eventos. O código a seguir faz referência programática à RoleList CheckBox na primeira visita à página e associa as funções no sistema a ela.

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 
          // Reference the SpecifyRolesStep WizardStep 
          WizardStep SpecifyRolesStep = RegisterUserWithRoles.FindControl("SpecifyRolesStep") as WizardStep; 

          // Reference the RoleList CheckBoxList 
          CheckBoxList RoleList = SpecifyRolesStep.FindControl("RoleList") as CheckBoxList; 

          // Bind the set of roles to RoleList 
          RoleList.DataSource = Roles.GetAllRoles(); 
          RoleList.DataBind(); 
     } 
}

O código acima deve parecer familiar. No tutorial Armazenandoinformações adicionais do usuário, usamos duas FindControl instruções para fazer referência a um controle da Web de dentro de um personalizadoWizardStep. E o código que associa as funções à CheckBoxList foi obtido anteriormente neste tutorial.

Para executar a segunda tarefa de programação, precisamos saber quando a etapa "Especificar Funções" foi concluída. Lembre-se de que CreateUserWizard tem um ActiveStepChanged evento , que é acionado sempre que o visitante navega de uma etapa para outra. Aqui, podemos determinar se o usuário chegou à etapa "Concluir"; Nesse caso, precisamos adicionar o usuário às funções selecionadas.

Crie um manipulador de eventos para o ActiveStepChanged evento e adicione o seguinte código:

protected void RegisterUserWithRoles_ActiveStepChanged(object sender, EventArgs e) 
{ 
     // Have we JUST reached the Complete step? 
     if (RegisterUserWithRoles.ActiveStep.Title == "Complete") 
     { 
          // Reference the SpecifyRolesStep WizardStep 
          WizardStep SpecifyRolesStep = RegisterUserWithRoles.FindControl("SpecifyRolesStep") as WizardStep; 

          // Reference the RoleList CheckBoxList 
          CheckBoxList RoleList = SpecifyRolesStep.FindControl("RoleList") as CheckBoxList; 

          // Add the checked roles to the just-added user 
          foreach (ListItem li in RoleList.Items) 

          { 
               if (li.Selected) 
                    Roles.AddUserToRole(RegisterUserWithRoles.UserName, li.Text); 
          } 
     } 
}

Se o usuário acabou de chegar à etapa "Concluído", o manipulador de eventos enumera os itens da RoleList CheckBoxList e o usuário que acabou de criar é atribuído às funções selecionadas.

Visite esta página por meio de um navegador. A primeira etapa do CreateUserWizard é a etapa padrão "Inscrever-se para sua nova conta", que solicita o nome de usuário, a senha, o email e outras informações importantes do novo usuário. Insira as informações para criar um novo usuário chamado Wanda.

Criar um novo usuário chamado Wanda

Figura 12: Criar um novo usuário chamado Wanda (clique para exibir a imagem em tamanho real)

Clique no botão "Criar Usuário". O CreateUserWizard chama internamente o Membership.CreateUser método , criando a nova conta de usuário e, em seguida, progride para a próxima etapa, "Especificar Funções". Aqui, as funções do sistema estão listadas. Marque a caixa de seleção Supervisores e clique em Avançar.

Tornar Wanda um membro da função supervisores

Figura 13: Tornar Wanda um membro da função Supervisores (clique para exibir a imagem em tamanho real)

Clicar em Avançar causa um postback e atualiza o ActiveStep para a etapa "Concluir". ActiveStepChanged No manipulador de eventos, a conta de usuário criada recentemente é atribuída à função Supervisores. Para verificar isso, retorne à UsersAndRoles.aspx página e selecione Supervisores no RoleList DropDownList. Como mostra a Figura 14, os Supervisores agora são compostos por três usuários: Bruce, Tito e Wanda.

Bruce, Tito e Wanda são todos supervisores

Figura 14: Bruce, Tito e Wanda são Todos Supervisores (Clique para exibir a imagem em tamanho real)

Resumo

A estrutura Funções oferece métodos para recuperar informações sobre funções e métodos de um usuário específico para determinar quais usuários pertencem a uma função especificada. Além disso, há vários métodos para adicionar e remover um ou mais usuários a uma ou mais funções. Neste tutorial, nos concentramos em apenas dois desses métodos: AddUserToRole e RemoveUserFromRole. Há variantes adicionais projetadas para adicionar vários usuários a uma única função e atribuir várias funções a um único usuário.

Este tutorial também incluiu uma olhada na extensão do controle CreateUserWizard para incluir um WizardStep para especificar as funções do usuário recém-criado. Essa etapa pode ajudar um administrador a simplificar o processo de criação de contas de usuário para novos usuários.

Neste ponto, vimos como criar e excluir funções e como adicionar e remover usuários de funções. Mas ainda não analisamos a aplicação da autorização baseada em função. No tutorial a seguir , examinaremos a definição de regras de autorização de URL em uma base função por função, bem como como limitar a funcionalidade no nível da página com base nas funções do usuário conectado no momento.

Programação feliz!

Leitura Adicional

Para obter mais informações sobre os tópicos discutidos neste tutorial, consulte os seguintes recursos:

Sobre o autor

Scott Mitchell, autor de vários livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Scott pode ser contatado em mitchell@4guysfromrolla.com ou através de seu blog em http://ScottOnWriting.NET.

Agradecimentos especiais a...

Esta série de tutoriais foi revisada por muitos revisores úteis. A revisora principal deste tutorial foi Teresa Murphy. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com