I am writing an MVC 4 web application with custom authentication and authorisation. When a user logs into the site, I create a a FormsAuthenticationTicket and store it in a cookie
public void SignIn(string userName, bool createPersistentCookie, string UserData)
{
if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
// Create and tuck away the cookie
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddDays(15), createPersistentCookie, UserData);
// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(authTicket);
//// Create the cookie.
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
HttpContext.Current.Response.Cookies.Add(faCookie);
}
The UserData string will be a pipe delimited string and it will always contain at least two items, UserID | UserRole. A user can be assigned to one or more roles, therefore, the UserData could look like this UserID | UserRole | UserRole | UserRole
I then have my own custom generic principal in Global.asax
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
// Get the authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
// If the cookie can't be found, don't issue the ticket
if (authCookie == null) return;
// Get the authentication ticket and rebuild the principal
// & identity
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
string[] UserData = authTicket.UserData.Split(new Char[] { '|' });
GenericIdentity userIdentity = new GenericIdentity(authTicket.Name);
GenericPrincipal userPrincipal = new GenericPrincipal(userIdentity, UserData);
Context.User = userPrincipal;
}
This all works fine, however, within my application, if a user has multiple roles, when they log in, I need to list their roles, and then let them select only one role to go and perform functionality based on the selected role.
I was thinking, to do this, maybe I could pass the role the user selects to a method, get their FormsAuthenticationTicket and update the UserData to reflect the role they have choosen. For example, a UserData string is created with 1|Manager|Applicant, then I need to list both roles and ask the user which role they want to perform functionality under, they select Manager and I then update their UserData within their FormsAuthenticationTicket to 1|Manager.
Is this even possible, or maybe there is a better way of doing this?
Any help would be greatly appreciated.
Thanks everyone.
You could always change FormsAuthenticationTicket
.
HttpCookie cookie = FormsAuthentication.GetAuthCookie(Username, true);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
var newticket = new FormsAuthenticationTicket(ticket.Version,
ticket.Name,
ticket.IssueDate,
ticket.Expiration,
true,
"new user data",
ticket.CookiePath);
cookie.Value = FormsAuthentication.Encrypt(newticket);
cookie.Expires = newticket.Expiration.AddHours(24);
HttpContext.Current.Response.Cookies.Set(cookie);
As I said in my comment, I feel this is very poor usability. However, if you're determined to do this, then Dzenan's approach would work (you essentially just strip out all the other roles after the user has selected which role he wants).
Another approach would be to add an additional field to your userdata, which is SelectedRole. Then create a custom IPrincipal that includes this field.
Another approach would be to store it as your own cookie, although I would make sure that you validate that you aren't setting a role that the user is not authorized for (ie if you set SelectedRole=Admin make sure the user has an Admin role before you use it).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With