patterncsharpMinor
Custom Authentication, Authorization, and Roles implementation
Viewed 0 times
rolesauthorizationauthenticationcustomandimplementation
Problem
I've got an MVC site, using
Authentication
There are three ways to sign-on:
All three get the user an auth cookie and start a session. The first two are used by visitors (session only) and the third for authors/admin with DB accounts.
A simple flags enum for permissions:
```
[Flags]
public enum Roles
{
Guest =
FormsAuthentication and custom service classes for Authentication, Authorization, Roles/Membership, etc.Authentication
There are three ways to sign-on:
- Email + Alias
- OpenID
- Username + Password
All three get the user an auth cookie and start a session. The first two are used by visitors (session only) and the third for authors/admin with DB accounts.
public class BaseFormsAuthenticationService : IAuthenticationService
{
// Disperse auth cookie and store user session info.
public virtual void SignIn(UserBase user, bool persistentCookie)
{
var vmUser = new UserSessionInfoViewModel { Email = user.Email, Name = user.Name, Url = user.Url, Gravatar = user.Gravatar };
if(user.GetType() == typeof(User)) {
// roles go into view model as string not enum, see Roles enum below.
var rolesInt = ((User)user).Roles;
var rolesEnum = (Roles)rolesInt;
var rolesString = rolesEnum.ToString();
var rolesStringList = rolesString.Split(',').Select(role => role.Trim()).ToList();
vmUser.Roles = rolesStringList;
}
// i was serializing the user data and stuffing it in the auth cookie
// but I'm simply going to use the Session[] items collection now, so
// just ignore this variable and its inclusion in the cookie below.
var userData = "";
var ticket = new FormsAuthenticationTicket(1, user.Email, DateTime.UtcNow, DateTime.UtcNow.AddMinutes(30), false, userData, FormsAuthentication.FormsCookiePath);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket) { HttpOnly = true };
HttpContext.Current.Response.Cookies.Add(authCookie);
HttpContext.Current.Session["user"] = vmUser;
}
}RolesA simple flags enum for permissions:
```
[Flags]
public enum Roles
{
Guest =
Solution
I'll take a stab at answering your questions and provide some suggestions:
-
If you have FormsAuthentication configured in
-
You probably want to override both
-
I think the session-vs-cookie question is largely preference, but I'd recommend going with the session for a few reasons. The biggest reason is that the cookie is transmitted with every request, and while right now you may only have a little bit of data in it, as time progresses who knows what you'll stuff in there. Add encryption overhead and it could get large enough to slow down requests. Storing it in the session also puts ownership of the data in your hands (versus putting it in the client's hands and relying on you to decrypt and use it). One suggestion I would make is wrapping that session access up in a static
-
I can't really speak to whether it is a good separation of concerns, but it looks like a good solution to me. It's not unlike other MVC authentication approaches I've seen. I'm using something very similar in my apps in fact.
One last question -- why did you build and set the FormsAuthentication cookie manually instead of using
Josh
-
If you have FormsAuthentication configured in
web.config, it will automatically pull the cookie for you, so you shouldn't have to do any manual population of the FormsIdentity. This is pretty easy to test in any case.-
You probably want to override both
AuthorizeCore and OnAuthorization for an effective authorization attribute. The AuthorizeCore method returns a boolean and is used to determine whether the user has access to a given resource. The OnAuthorization doesn't return and is generally used to trigger other things based on the authentication status.-
I think the session-vs-cookie question is largely preference, but I'd recommend going with the session for a few reasons. The biggest reason is that the cookie is transmitted with every request, and while right now you may only have a little bit of data in it, as time progresses who knows what you'll stuff in there. Add encryption overhead and it could get large enough to slow down requests. Storing it in the session also puts ownership of the data in your hands (versus putting it in the client's hands and relying on you to decrypt and use it). One suggestion I would make is wrapping that session access up in a static
UserContext class, similar to HttpContext, so you could just make a call like UserContext.Current.UserData. I can provide some code for this if you need some suggestions. This approach will let you hide the implementation so you can change from session to cookie and back without affecting other code that uses it.-
I can't really speak to whether it is a good separation of concerns, but it looks like a good solution to me. It's not unlike other MVC authentication approaches I've seen. I'm using something very similar in my apps in fact.
One last question -- why did you build and set the FormsAuthentication cookie manually instead of using
FormsAuthentication.SetAuthCookie? Just curious.Josh
Context
StackExchange Code Review Q#7234, answer score: 6
Revisions (0)
No revisions yet.