Hi,
When using Role Based Authorization, we can set the Roles of a user at the application level by specifying it in the Global.asax's Application_AuthenticateRequest method.
As soon as a user is authenticated, it will fetch his roles from the database and assign it to him so that we can use the User.IsInRole("RoleName") to check his role and perform actions based on the same.
You can find many resources on the above topic on how to set the roles. However, one disadvantage is that on every page you check the Role, the DB call is made which might affect the performance of the application.
To resolve that we can set the role cookie manually through code so that it doesnt make the DB call for every request.
The following code segment provides the code for the total operation.
In the Global.asax's code behind file, locate the following method and put the code inside as follows:-
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
AssignRolesToUser();
}
Then place the following code segment.
private void AssignRolesToUser()
{
if (Context.Request.IsAuthenticated)
{
// Retrieve user's identity from context user
FormsIdentity ident = (FormsIdentity) Context.User.Identity;
// Retrieve roles from the authentication ticket userdata field
string[] roles = ident.Ticket.UserData.Split('|');
// If we didn't load the roles before, go to the DB
if (roles[0].Length == 0)
{
// Fetch roles from the database.
roles = FetchRoles();
// Store roles inside the Forms ticket.
FormsAuthenticationTicket newticket = new FormsAuthenticationTicket(
ident.Ticket.Version,
ident.Ticket.Name,
ident.Ticket.IssueDate,
ident.Ticket.Expiration,
ident.Ticket.IsPersistent,
String.Join("|", roles),
ident.Ticket.CookiePath);
// Create the cookie.
HttpCookie authCookie = new HttpCookie(
FormsAuthentication.FormsCookieName,
FormsAuthentication.Encrypt(newticket));
authCookie.Path = FormsAuthentication.FormsCookiePath + "; HttpOnly; noScriptAccess";
authCookie.Secure = FormsAuthentication.RequireSSL;
if (newticket.IsPersistent)
authCookie.Expires = newticket.Expiration;
Context.Response.Cookies.Add(authCookie);
}
// Create principal and attach to user
Context.User = new System.Security.Principal.GenericPrincipal(ident, roles);
}
}
private string[] FetchRoles()
{
// Fetch roles from the database somehow.
ArrayList roleList = new ArrayList();
SqlDataReader objRdr=null;
SqlConnection objCon = new SqlConnection("Your connection string here);
SqlCommand objCmd = new SqlCommand("spRoles", objCon);
objCmd.CommandType = CommandType.StoredProcedure;
objCmd.Parameters.Add("@Username", User.Identity.Name.ToString());
try
{
objCon.Open();
objRdr = objCmd.ExecuteReader();
if(objRdr.HasRows)
{
while(objRdr.Read())
{
roleList.Add(objRdr["RoleName"].ToString());
}
}
objRdr.Close();
}
catch
{
return null;
}
finally
{
objCon.Close();
objCon.Dispose();
}
return (string[])roleList.ToArray (typeof (string));
}
The procedure spRoles will fetch the roles based on the UserName which is passed as a parameter.
The code for the procedure is as below:-
CREATE PROCEDURE spRoles
(
@Username varchar(50)
)
AS
SELECT G.Name
FROM Roles R
INNER JOIN Groups G ON
R.GroupID = G.GroupID
INNER JOIN Users U ON
R.UserID = U.UserID AND U.Username = @Username
In the above procedure I have used three sample tables Users, Groups and Roles
Users - will contain UserID, UserName and password
Groups - will contain GroupID and Name i.e. Admin, Moderator, User
Roles - will contain the UserID and their GroupID i.e. group they are assigned to.
Once you set the above Roles, thereafter in your pages, you can just use
if(Context.User.IsInRole("RoleName"))
{
// do something
}
Queries, Comments and Suggestions are welcome.
Thanks.