Monday, 2 March 2015

Assign Roles to Users in ASP.Net Form Based Authentication

Database
I am making use of the database tables.
Users
Assign Roles to Users in ASP.Net Form Based Authentication
 
Roles
Assign Roles to Users in ASP.Net Form Based Authentication
 
The Roles table has two Roles i.e. Administrator and User
Assign Roles to Users in ASP.Net Form Based Authentication
 
Note: You can download the database table SQL by clicking the download link below.
          Download SQL file
 
 
Login Page
This page will be used for allowing users login into the site. I have used the same code and design as used in the article Simple User Login Form example in ASP.Net with little modifications for implementing roles.
 
HTML Markup
The HTML markup consists of an ASP.Net Login control for which the OnAuthenticate event handler has been specified.
<asp:Login ID = "Login1" runat = "server" OnAuthenticate= "ValidateUser"></asp:Login>
 
Assign Roles to Users in ASP.Net Form Based Authentication
 
 
Namespaces
You will need to import the following namespaces.
C#
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.Web.Security;
 
VB.Net
Imports System.Data
Imports System.Configuration
Imports System.Data.SqlClient
Imports System.Web.Security
 
 
Stored Procedure to Validate the User Credentials and get the Role
The following stored procedure is used to validate the user credentials and it also gets the assigned role, this stored procedure first checks whether the username and password are correct else returns -1.
If the username and password are correct but the user has not been activated then the code returned is -2.
If the username and password are correct and the user account has been activated then UserId and the Role is returned by the stored procedure.
CREATE PROCEDURE [dbo].[Validate_User]
      @Username NVARCHAR(20),
      @Password NVARCHAR(20)
AS
BEGIN
      SET NOCOUNT ON;
      DECLARE @UserId INT, @LastLoginDate DATETIME, @RoleId INT
     
      SELECT @UserId = UserId, @LastLoginDate = LastLoginDate, @RoleId = RoleId
      FROM Users WHERE Username = @Username AND [Password] = @Password
     
      IF @UserId IS NOT NULL
      BEGIN
            IF NOT EXISTS(SELECT UserId FROM UserActivation WHERE UserId = @UserId)
            BEGIN
                  UPDATE Users
                  SET LastLoginDate = GETDATE()
                  WHERE UserId = @UserId
                 
                  SELECT @UserId [UserId],
                              (SELECT RoleName FROM Roles
                               WHERE RoleId = @RoleId) [Roles] -- User Valid
            END
            ELSE
            BEGIN
                  SELECT -2 [UserId], '' [Roles]-- User not activated.
            END
      END
      ELSE
      BEGIN
            SELECT -1 [UserId], '' [Roles] -- User invalid.
      END
END
 
 
Validating the User Credentials and determining the Role
The below event handler gets called when the Log In button is clicked. Here the Username and Password entered by the user is passed to the stored procedure and if the authentication is successful the UserId and the Role is returned.
The returned UserId and Role is used to create a FormsAuthentication ticket and the user is redirected either to the default page specified in the Web.Config or to the URL specified in the ReturnUrl QueryString parameter.
C#
protected void ValidateUser(object sender, EventArgs e)
{
    int userId = 0;
    string roles = string.Empty;
    string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
    using (SqlConnection con = new SqlConnection(constr))
    {
        using (SqlCommand cmd = new SqlCommand("Validate_User"))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("@Username", Login1.UserName);
            cmd.Parameters.AddWithValue("@Password", Login1.Password);
            cmd.Connection = con;
            con.Open();
            SqlDataReader reader = cmd.ExecuteReader();
            reader.Read();
            userId = Convert.ToInt32(reader["UserId"]);
            roles = reader["Roles"].ToString();
            con.Close();
        }
        switch (userId)
        {
            case -1:
                Login1.FailureText = "Username and/or password is incorrect.";
                break;
            case -2:
                Login1.FailureText = "Account has not been activated.";
                break;
            default:
                FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, Login1.UserName, DateTime.Now, DateTime.Now.AddMinutes(2880), Login1.RememberMeSet, roles, FormsAuthentication.FormsCookiePath);
                string hash = FormsAuthentication.Encrypt(ticket);
                HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
 
                if (ticket.IsPersistent)
                {
                    cookie.Expires = ticket.Expiration;
                }
                Response.Cookies.Add(cookie);
                Response.Redirect(FormsAuthentication.GetRedirectUrl(Login1.UserName, Login1.RememberMeSet));
                break;
        }
    }
}
 
VB.Net
Protected Sub ValidateUser(sender As Object, e As EventArgs)
    Dim userId As Integer = 0
    Dim roles As String = String.Empty
    Dim constr As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
    Using con As New SqlConnection(constr)
        Using cmd As New SqlCommand("Validate_User")
            cmd.CommandType = CommandType.StoredProcedure
            cmd.Parameters.AddWithValue("@Username", Login1.UserName)
            cmd.Parameters.AddWithValue("@Password", Login1.Password)
            cmd.Connection = con
            con.Open()
            Dim reader As SqlDataReader = cmd.ExecuteReader()
            reader.Read()
            userId = Convert.ToInt32(reader("UserId"))
            roles = reader("Roles").ToString()
            con.Close()
        End Using
        Select Case userId
            Case -1
                Login1.FailureText = "Username and/or password is incorrect."
                Exit Select
            Case -2
                Login1.FailureText = "Account has not been activated."
                Exit Select
            Case Else
                Dim ticket As New FormsAuthenticationTicket(1, Login1.UserName, DateTime.Now, DateTime.Now.AddMinutes(2880), Login1.RememberMeSet, roles, _
                 FormsAuthentication.FormsCookiePath)
                Dim hash As String = FormsAuthentication.Encrypt(ticket)
                Dim cookie As New HttpCookie(FormsAuthentication.FormsCookieName, hash)
 
                If ticket.IsPersistent Then
                    cookie.Expires = ticket.Expiration
                End If
                Response.Cookies.Add(cookie)
                Response.Redirect(FormsAuthentication.GetRedirectUrl(Login1.UserName, Login1.RememberMeSet))
                Exit Select
        End Select
    End Using
End Sub
 
Inside Application_AuthenticateRequest event of the Global.asax file, the Roles are fetched from the FormsAuthentication Ticket and assigned to the HttpContext User object. This way the Role is available throughout the Application through the Context.
C#
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    if (HttpContext.Current.User != null)
    {
        if (HttpContext.Current.User.Identity.IsAuthenticated)
        {
            if (HttpContext.Current.User.Identity is FormsIdentity)
            {
                FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
                FormsAuthenticationTicket ticket = id.Ticket;
                string userData = ticket.UserData;
                string[] roles = userData.Split(',');
                HttpContext.Current.User = new GenericPrincipal(id, roles);
            }
        }
    }
}
 
VB.Net
Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs)
    If HttpContext.Current.User IsNot Nothing Then
        If HttpContext.Current.User.Identity.IsAuthenticated Then
            If TypeOf HttpContext.Current.User.Identity Is FormsIdentity Then
                Dim id As FormsIdentity = DirectCast(HttpContext.Current.User.Identity, FormsIdentity)
                Dim ticket As FormsAuthenticationTicket = id.Ticket
                Dim userData As String = ticket.UserData
                Dim roles As String() = userData.Split(","c)
                HttpContext.Current.User = New GenericPrincipal(id, roles)
            End If
        End If
    End If
End Sub
 
 
Populating the Users along with Roles in GridView control
HTML Markup
The HTML Markup consists of an ASP.Net GridView with a BoundField column for displaying Username and two TemplateField columns one consisting of an ASP.Net DropDownList and other consisting of a Button. The GridView has been assigned an OnRowDataBound event handler.
<asp:Panel ID="pnlAssignRoles" runat="server" Visible="false">
    <asp:GridView ID="gvUsers" runat="server" AutoGenerateColumns="false" OnRowDataBound="OnRowDataBound">
        <Columns>
            <asp:BoundField DataField="Username" HeaderText="Username" />
            <asp:TemplateField HeaderText="Role">
                <ItemTemplate>
                    <asp:DropDownList ID="ddlRoles" runat="server">
                    </asp:DropDownList>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Role">
                <ItemTemplate>
                    <asp:Button ID="btnUpdate" Text="Update" runat="server" CommandArgument='<%# Eval("UserId") %>'
                        OnClick="UpdateRole" />
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>
</asp:Panel>
 
Once the user logs in, a check is performed whether User belongs to Administrator role. If the logged in user is an Administrator then the GridView is populated.
Inside the OnRowDataBound event handler, the DropDownList control in each GridView Row is populated with the records from the Roles table.
Once the DropDownList is populated, the assigned Role to the user is selected.
C#
protected void Page_Load(object sender, EventArgs e)
{
    if (!this.IsPostBack)
    {
        if (!this.Page.User.Identity.IsAuthenticated)
        {
            Response.Redirect("~/Login.aspx");
        }
        if (this.Page.User.IsInRole("Administrator"))
        {
            pnlAssignRoles.Visible = true;
            gvUsers.DataSource = GetData("SELECT UserId, Username, RoleId FROM Users");
            gvUsers.DataBind();
        }
    }
}
 
private DataTable GetData(string query)
{
    string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
    using (SqlConnection con = new SqlConnection(constr))
    {
        using (SqlCommand cmd = new SqlCommand(query))
        {
            cmd.CommandType = CommandType.Text;
            cmd.Connection = con;
            using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
            {
                DataTable dt = new DataTable();
                sda.Fill(dt);
                return dt;
            }
        }
    }
}
 
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        DropDownList ddlRoles = (e.Row.FindControl("ddlRoles") as DropDownList);
        ddlRoles.DataSource = GetData("SELECT RoleId, RoleName FROM Roles");
        ddlRoles.DataTextField = "RoleName";
        ddlRoles.DataValueField = "RoleId";
        ddlRoles.DataBind();
 
        string assignedRole = (e.Row.DataItem as DataRowView)["RoleId"].ToString();
        ddlRoles.Items.FindByValue(assignedRole).Selected = true;
    }
}
 
VB.Net
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    If Not Me.IsPostBack Then
        If Not Me.Page.User.Identity.IsAuthenticated Then
            Response.Redirect("~/Login.aspx")
        End If
        If Me.Page.User.IsInRole("Administrator") Then
            pnlAssignRoles.Visible = True
            gvUsers.DataSource = GetData("SELECT UserId, Username, RoleId FROM Users")
            gvUsers.DataBind()
        End If
    End If
End Sub
 
Private Function GetData(query As String) As DataTable
    Dim constr As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
    Using con As New SqlConnection(constr)
        Using cmd As New SqlCommand(query)
            cmd.CommandType = CommandType.Text
            cmd.Connection = con
            Using sda As New SqlDataAdapter(cmd)
                Dim dt As New DataTable()
                sda.Fill(dt)
                Return dt
            End Using
        End Using
    End Using
End Function
 
Protected Sub OnRowDataBound(sender As Object, e As GridViewRowEventArgs)
    If e.Row.RowType = DataControlRowType.DataRow Then
        Dim ddlRoles As DropDownList = TryCast(e.Row.FindControl("ddlRoles"), DropDownList)
        ddlRoles.DataSource = GetData("SELECT RoleId, RoleName FROM Roles")
        ddlRoles.DataTextField = "RoleName"
        ddlRoles.DataValueField = "RoleId"
        ddlRoles.DataBind()
 
        Dim assignedRole As String = TryCast(e.Row.DataItem, DataRowView)("RoleId").ToString()
        ddlRoles.Items.FindByValue(assignedRole).Selected = True
    End If
End Sub
 
Assign Roles to Users in ASP.Net Form Based Authentication
 
Assign and update Roles to Users
When the Update button is clicked, the UserId is fetched from the CommandArgument property and the RoleId is fetched from the DropDownList.
Finally the Role of the User is updated in the database table.
C#
protected void UpdateRole(object sender, EventArgs e)
{
    GridViewRow row = ((sender as Button).NamingContainer as GridViewRow);
    int userId = int.Parse((sender as Button).CommandArgument);
    int roleId = int.Parse((row.FindControl("ddlRoles") as DropDownList).SelectedItem.Value);
    string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
    using (SqlConnection con = new SqlConnection(constr))
    {
        using (SqlCommand cmd = new SqlCommand("UPDATE Users SET RoleId = @RoleId WHERE UserId = @UserId"))
        {
            cmd.Parameters.AddWithValue("@UserId", userId);
            cmd.Parameters.AddWithValue("@RoleId", roleId);
            cmd.CommandType = CommandType.Text;
            cmd.Connection = con;
            con.Open();
            cmd.ExecuteNonQuery();
            con.Close();
        }
    }
}
 
VB.Net
Protected Sub UpdateRole(sender As Object, e As EventArgs)
    Dim row As GridViewRow = TryCast(TryCast(sender, Button).NamingContainer, GridViewRow)
    Dim userId As Integer = Integer.Parse(TryCast(sender, Button).CommandArgument)
    Dim roleId As Integer = Integer.Parse(TryCast(row.FindControl("ddlRoles"), DropDownList).SelectedItem.Value)
    Dim constr As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
    Using con As New SqlConnection(constr)
        Using cmd As New SqlCommand("UPDATE Users SET RoleId = @RoleId WHERE UserId = @UserId")
            cmd.Parameters.AddWithValue("@UserId", userId)
            cmd.Parameters.AddWithValue("@RoleId", roleId)
            cmd.CommandType = CommandType.Text
            cmd.Connection = con
            con.Open()
            cmd.ExecuteNonQuery()
            con.Close()
        End Using
    End Using
End Sub
 
Updated Role displayed on page
Assign Roles to Users in ASP.Net Form Based Authentication

No comments:

Post a Comment