Will Unity Framework Remove cookies from Context in MVC 5 - asp.net-mvc

I'm creating an application that have unity framework for dependency injection so my Account Controller is following and that contain Login Action
public class AccountController : Controller
{
private readonly IUserService userService;
public AccountController(IUserService userService)
{
this.userService = userService;
}
public ActionResult Login()
{
return View();
}
[HttpPost]
[AllowAnonymous]
//[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
string message = "";
var user = userService.UserExists(model, out message);
if (user != null)
{
CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
serializeModel.UserId = Convert.ToInt32(user.Id);
serializeModel.EmailId = user.EmailId;
serializeModel.FirstName = user.FirstName;
serializeModel.LastName = user.LastName;
serializeModel.role = user.Role;
string userData = JsonConvert.SerializeObject(serializeModel,Formatting.Indented,
new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
user.EmailId,
DateTime.Now,
model.RememberMe ? DateTime.Now.AddDays(3) : DateTime.Now.AddHours(3),
model.RememberMe ? true : false,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
faCookie.Expires = model.RememberMe ? DateTime.Now.AddDays(3) : DateTime.Now.AddHours(3);
Response.Cookies.Add(faCookie);
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "Incorrect username and/or password");
}
return View(model);
}
}
.In login action I'm doing following
1) Checking User Is Existed Or Not if existed then adding FormsAuthentication Cookie .
but when I using IUserService (Interface for DI ) then cookie is deleted when redirect to another action .
2) But if I remove DI from controller then Cookie is persisted .
whats wrong I'm finding answer from couple of days .
please give me solution I want DI and Cookie Both .
Thanks in advanced .

Related

GetExternalLoginInfoAsync returns null MVC

I receive the following code error when trying to run my MVC application from localhost using Microsoft AD. When debugging the application I noticed that GetExternalLoginInfoAsync returns null. However, the application runs fine on the web. What am I missing? Somebody please help. I have posted my code below the error message.
Server Error in '/' Application.
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
Line 140: {
Line 141: ExternalLoginInfo loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
Line 142: ClaimsIdentity claimsIdentity = loginInfo.ExternalIdentity;
Line 143: ApplicationUser applicationUser = new ApplicationUser(claimsIdentity);
Line 144: IdentityResult result = await UserManager.PersistAsync(applicationUser);
My code:
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using SampleQuoteTracker.Models;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace SampleQuoteTracker.Controllers
{
/// <summary>
/// Provides methods for accepting and desplaying account authenication and creating new accounts.
/// </summary>
public class AccountController : Controller
{
//
// GET: /Account/Login
public ActionResult Login(string returnUrl)
{
ViewBag.Title = "Log In";
LoginViewModel loginViewModel = new LoginViewModel()
{
ReturnUrl = returnUrl
};
return View(loginViewModel);
}
//
// POST: /Account/Login
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Login(LoginViewModel model)
{
// seed return object optimistically
AjaxResultModel loginResult = new AjaxResultModel
{
Status = "Valid",
ReturnUrl = GetLocalUrl(model.ReturnUrl),
Message = null
};
if (Request.IsAjaxRequest())
{
if (!ModelState.IsValid)
{
loginResult.Status = "Invalid";
loginResult.Message = Tools.ListModelStateErrors(ModelState);
}
if (loginResult.Status == "Valid")
{
SignInStatus result = await SignInManager.PasswordSignInAsync(
model.Email,
model.Password,
model.RememberMe,
shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
loginResult.Status = "Success";
break;
case SignInStatus.LockedOut:
loginResult.Status = "LockOut";
loginResult.Message = AlertMessages.AccountLockOut;
break;
case SignInStatus.Failure:
default:
loginResult.Status = "Failure";
loginResult.Message = AlertMessages.AuthenticationFailure;
break;
}
}
}
return Json(loginResult);
}
//
// POST: /Account/LogOff
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
//AuthenticationManager.SignOut();
//return RedirectToAction("SignOutCallback");
return null;
}
public void SignIn(string returnUrl = "/")
{
if (returnUrl == "/")
{
returnUrl = Request.ApplicationPath;
}
Uri baseUri = new UriBuilder(Request.Url.Scheme, Request.Url.Host, Request.Url.Port).Uri;
Uri uri = new Uri(baseUri, returnUrl);
// If this action is called and the user is already authenticated,
// it means the user is not a member of the appropriate role for
// the controller/action requested.
if (Request.IsAuthenticated)
{
RouteValueDictionary values = RouteDataContext.RouteValuesFromUri(uri);
string controllerName = (string)values["controller"];
string actionName = (string)values["action"];
string errorUrl = Url.Action("Error",
routeValues: new
{
message = "You are not authorized to view this content",
controllerName,
actionName
});
Response.Redirect(errorUrl, true);
}
else
{
// https://stackoverflow.com/a/21234614
// Activate the session before login to generate the authentication cookie correctly.
Session["Workaround"] = 0;
// Send an OpenID Connect sign-in request.
string externalLoginCallback = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
AuthenticationManager.Challenge(new AuthenticationProperties { RedirectUri = externalLoginCallback },
OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
}
//public IAuthenticationManager AuthenticationManager
//{
// get { return HttpContext.GetOwinContext().Authentication; }
//}
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
ExternalLoginInfo loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
ClaimsIdentity claimsIdentity = loginInfo.ExternalIdentity;
ApplicationUser applicationUser = new ApplicationUser(claimsIdentity);
IdentityResult result = await UserManager.PersistAsync(applicationUser);
if (result.Succeeded)
{
claimsIdentity = await applicationUser.GenerateUserIdentityAsync(UserManager);
}
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = false }, claimsIdentity);
return Redirect(returnUrl);
}
[Authorize]
public void SignOut()
{
string callbackUrl = Url.Action("SignOutCallback", "Account", null, Request.Url.Scheme);
AuthenticationProperties properties = new AuthenticationProperties { RedirectUri = callbackUrl };
AuthenticationManager.SignOut(
properties,
OpenIdConnectAuthenticationDefaults.AuthenticationType,
CookieAuthenticationDefaults.AuthenticationType,
Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
}
public ActionResult Error(string message, string controllerName = "Account", string actionName = "SignIn")
{
Exception exception = new Exception(message);
HandleErrorInfo handleErrorInfo = new HandleErrorInfo(exception, controllerName, actionName);
return View("Error", handleErrorInfo);
}
public ActionResult SignOutCallback()
{
if (Request.IsAuthenticated)
{
// Redirect to home page if the user is authenticated.
return RedirectToAction("Index", "Home");
}
return View();
}
protected override void Dispose(bool disposing)
{
if (disposing && UserManager != null)
{
UserManager.Dispose();
UserManager = null;
}
base.Dispose(disposing);
}
#region Helpers
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
private IAuthenticationManager _authenticationManager;
// Used for XSRF protection when adding external logins
private const string XsrfKey = "XsrfId";
/// <summary>
/// Gets a reference to the <see cref="ApplicationSignInManager"/>.
/// </summary>
protected ApplicationSignInManager SignInManager
{
get
{
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
private set { _signInManager = value; }
}
protected ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
protected IAuthenticationManager AuthenticationManager
{
get
{
return _authenticationManager ?? HttpContext.GetOwinContext().Authentication;
}
private set
{
_authenticationManager = value;
}
}
/// <summary>
/// Ensures the <paramref name="returnUrl"/> belongs to this application.
/// <para>We don't want to redirect to a foreign page after authentication.</para>
/// </summary>
/// <param name="returnUrl">a <see cref="System.String"/> containing the page address that required authorization.</param>
/// <returns>a <see cref="System.String"/> containing a local page address.</returns>
private string GetLocalUrl(string returnUrl)
{
if (!Url.IsLocalUrl(returnUrl))
{
return Url.Action("Index", "Home");
}
return returnUrl;
}
private class ChallengeResult : HttpUnauthorizedResult
{
public ChallengeResult(string provider, string redirectUri)
: this(provider, redirectUri, null)
{
}
public ChallengeResult(string provider, string redirectUri, string userId)
{
LoginProvider = provider;
RedirectUri = redirectUri;
UserId = userId;
}
public string LoginProvider { get; set; }
public string RedirectUri { get; set; }
public string UserId { get; set; }
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
if (UserId != null)
{
properties.Dictionary[XsrfKey] = UserId;
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
}
}
private class RouteDataContext : HttpContextBase
{
public override HttpRequestBase Request { get; }
private RouteDataContext(Uri uri)
{
string url = uri.GetLeftPart(UriPartial.Path);
string qs = uri.GetComponents(UriComponents.Query, UriFormat.UriEscaped);
Request = new HttpRequestWrapper(new HttpRequest(null, url, qs));
}
public static RouteValueDictionary RouteValuesFromUri(Uri uri)
{
return RouteTable.Routes.GetRouteData(new RouteDataContext(uri)).Values;
}
}
#endregion
}
}
Eventually the ExternalCookie is removed when the Owin middleware inspects the context.
That way AuthenticationManager.GetExternalLoginInfo() returns null after logging in, the cookie holding the info has been removed and replaced by a ApplicationCookie.
So add the following in your Startup.cs
public void ConfigureAuth(IAppBuilder app)
{
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/LogOn")
});
....
}
For more details, you could refer to this article.

Authorize Attribute with Roles

I want to implement my custom authorization, I wonder what is wrong with my code even I got the user credentials correctly it still redirects me to my Login Method, please see the code below
Edit: I have successfully implemented the Authorize Attribute with Roles, for future readers please see code below
Login Controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login (AdminViewModels.Login viewModel, string returnURL)
{
if (!ModelState.IsValid)
{
return View(viewModel);
}
PasswordHasher passwordVerify = new PasswordHasher();
var query = (from acc in db.accounts.Where(x => x.username == viewModel.Username)
select new { acc.username, acc.password}).FirstOrDefault();
if (query != null)
{
if (ModelState.IsValid)
{
var result = passwordVerify.VerifyHashedPassword(query.password, viewModel.Password);
switch (result)
{
case PasswordVerificationResult.Success:
//set forms ticket to be use in global.asax
SetupFormsAuthTicket(viewModel.Username, viewModel.rememeberMe);
return RedirectToLocal(returnURL);
case PasswordVerificationResult.Failed:
ModelState.AddModelError("", "Wrong Username or Password");
return View(viewModel);
}
}
}
return View(viewModel);
}
Forms Auth Ticket
private account SetupFormsAuthTicket(string userName, bool persistanceFlag)
{
account user = new account();
var userId = user.id;
var userData = userId.ToString(CultureInfo.InvariantCulture);
var authTicket = new FormsAuthenticationTicket(1, //version
userName, // user name
DateTime.Now, //creation
DateTime.Now.AddMinutes(20), //Expiration
persistanceFlag, //Persistent
userData);
var encTicket = FormsAuthentication.Encrypt(authTicket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
return user;
}
Global.asax
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//take out user name from cookies
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string[] roles = null;
trainingEntities db = new trainingEntities();
//query database to get user roles
var query = (from acc in db.account_roles where acc.account.username == username select acc.role.role_name).ToArray();
roles = query;
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles);
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
Now you can use [Authorize(Roles = "Admin")]
to any action method or on top of controller
I have successfully implemented the Authorize Attribute with Roles, for future readers please see code below.
Login Controller
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login (AdminViewModels.Login viewModel, string returnURL)
{
if (!ModelState.IsValid)
{
return View(viewModel);
}
PasswordHasher passwordVerify = new PasswordHasher();
var query = (from acc in db.accounts.Where(x => x.username == viewModel.Username)
select new { acc.username, acc.password}).FirstOrDefault();
if (query != null)
{
if (ModelState.IsValid)
{
var result = passwordVerify.VerifyHashedPassword(query.password, viewModel.Password);
switch (result)
{
case PasswordVerificationResult.Success:
//set forms ticket to be use in global.asax
SetupFormsAuthTicket(viewModel.Username, viewModel.rememeberMe);
return RedirectToLocal(returnURL);
case PasswordVerificationResult.Failed:
ModelState.AddModelError("", "Wrong Username or Password");
return View(viewModel);
}
}
}
return View(viewModel);
}
FormsAuthTicket
private account SetupFormsAuthTicket(string userName, bool persistanceFlag)
{
account user = new account();
var userId = user.id;
var userData = userId.ToString(CultureInfo.InvariantCulture);
var authTicket = new FormsAuthenticationTicket(1, //version
userName, // user name
DateTime.Now, //creation
DateTime.Now.AddMinutes(20), //Expiration
persistanceFlag, //Persistent
userData);
var encTicket = FormsAuthentication.Encrypt(authTicket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
return user;
}
Global.asax
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//take out user name from cookies
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string[] roles = null;
trainingEntities db = new trainingEntities();
//query database to get user roles
var query = (from acc in db.account_roles where acc.account.username == username select acc.role.role_name).ToArray();
roles = query;
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles);
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
Now you can use [Authorize(Roles = "Admin")]
to any action method or on top of controller
as I see in ControllerLogin attribute it is now being applied in a variable, when it should be applied to a method or a class
[CustomAuthorization(UserRole="Admin")]
// GET: Manage
private trainingEntities db = new trainingEntities();
public ActionResult Index()
{
return View();
}
Private trainingEntities dB = new TrainingEntities();
[CustomAuthorization(UserRole="Admin")]
Public ActionResult Index()
{
//yourcode
}

MVC Login with repository?

I am trying to validates users with login view,controller and repository
Actions result in controller
[HttpPost]
public ActionResult Login(Models.UserModel user)
{
CartLibrary.Repository.UserRepository objuserrepository = new CartLibrary.Repository.UserRepository();
objuserrepository.Login(user.Username, user.Password);
return RedirectToAction("Index", "Orders");
}
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
Method in repository
public string Login(string Username, string Password )
{
if (!DB.Users.Any(x => x.Username == Username && x.Password == Password))
{
return Username;
}
throw new UnauthorizedAccessException();
return Username;
}
In your Login method you just return string (username).....but you don't set any cookies so......????
So you can after your login method write code:
if(String.IsNullOrEmpty(objuserrepository.Login(user.Username,user.Password))
{
FormsAuthentication.SetAuthCookie(
this.TextBox_username.Text.Trim(), flase);
FormsAuthenticationTicket ticket1 =
new FormsAuthenticationTicket(
1, // version
this.TextBox_username.Text.Trim(), // get username from the form
DateTime.Now, // issue time is now
DateTime.Now.AddMinutes(10), // expires in 10 minutes
false, // cookie is not persistent
"HR" // role assignment is stored
// in userData
);
HttpCookie cookie1 = new HttpCookie(
FormsAuthentication.FormsCookieName,
FormsAuthentication.Encrypt(ticket1) );
Response.Cookies.Add(cookie1);
}

Unable to retrieve UserData on Forms authentication ticket

I am trying to get some custom field values from my authentication ticket by running the following code in my controller -
[HttpPost]
public ActionResult Add(AddCustomerModel customer)
{
customer.DateCreated = DateTime.Now;
customer.CreatedBy = ((CustomPrincipal)(HttpContext.User)).Id;
customer.LastUpdated = DateTime.Now;
customer.LastUpdateBy = ((CustomPrincipal)(HttpContext.User)).Id;
if (ModelState.IsValid)
{
_customerService.AddCustomer(customer);
return RedirectToAction("Index");
}
return View(customer);
}
When I try and set the CreatedBy field for the new customer, I get the following error -
Unable to cast object of type 'System.Security.Principal.GenericPrincipal' to type 'GMS.Core.Models.CustomPrincipal'.
My userData field within the FormsAuthenticationTicket is set with a JSON string which contains two fields - Id and FullName.
Here is my login method on the controller -
[HttpPost]
[AllowAnonymous]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (Membership.ValidateUser(model.EmailAddress, model.Password))
{
LoginModel user = _userService.GetUserByEmail(model.EmailAddress);
CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
serializeModel.Id = user.ID;
serializeModel.FullName = user.EmailAddress;
//serializeModel.MergedRights = user.MergedRights;
JavaScriptSerializer serializer = new JavaScriptSerializer();
string userData = serializer.Serialize(serializeModel);
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
user.EmailAddress,
DateTime.Now,
DateTime.Now.AddHours(12),
false,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
Response.Cookies.Add(faCookie);
return RedirectToAction("Index", "Dashboard");
}
return RedirectToAction("Index");
}
Any ideas where I am going wrong?
To retrieve the userdata from cookies you can use the following code
FormsIdentity formsIdentity = HttpContext.Current.User.Identity as FormsIdentity;
FormsAuthenticationTicket ticket = formsIdentity.Ticket;
string userData = ticket.UserData;
You need to create and AuthenticationFilter to change your GenericPrincipal to your CustomPrincipal
public class FormAuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter
{
private readonly IResolver<HttpContextWrapper> httpContextWrapper;
private readonly IResolver<ISecurityProvider> securityProviderResolver;
public FormAuthenticationFilter(IResolver<HttpContextWrapper> httpContextWrapper, IResolver<ISecurityProvider> securityProviderResolver)
{
this.httpContextWrapper = httpContextWrapper;
this.securityProviderResolver = securityProviderResolver;
}
public void OnAuthentication(AuthenticationContext filterContext)
{
if (filterContext.Principal != null && !filterContext.IsChildAction)
{
if (filterContext.Principal.Identity.IsAuthenticated &&
filterContext.Principal.Identity.AuthenticationType.Equals("Forms", StringComparison.InvariantCultureIgnoreCase))
{
// Replace form authenticate identity
var formIdentity = filterContext.Principal.Identity as FormsIdentity;
if (formIdentity != null)
{
var securityProvider = this.securityProviderResolver.Resolve();
var principal = securityProvider.GetPrincipal(filterContext.Principal.Identity.Name, formIdentity.Ticket.UserData);
if (principal != null)
{
filterContext.Principal = principal;
this.httpContextWrapper.Resolve().User = principal;
}
}
}
}
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
}
}
And then register that filter to GlobalFilter
GlobalFilters.Filters.Add(new FormAuthenticationFilter());
The HttpContextWrapper in my code is just the wrapper of HttpContext.Current. You can change it to whatever you need. And the IAuthenticationFilter only exist in MVC 5.

mvc 4 can not be custom Authorize roles

HomeController
[Authorize(Roles = "Member")]
public ActionResult Contact()
{
return View();
}
Global.asax
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
//Construst the GeneralPrincipal and FormsIdentity objects
var authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (null == authCookie)
{
//no authentication cokie present
return;
}
var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (null == authTicket)
{
//could not decrypt cookie
return;
}
//get the role
var role = authTicket.UserData.Split(new[] { ',' });
var id = new FormsIdentity(authTicket);
Context.User = new GenericPrincipal(id, role);
}
AccountController
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && _userbll.ValidateUser(model.UserName, model.Password))
{
var ticket = new FormsAuthenticationTicket(1, model.UserName, DateTime.Now, model.RememberMe ? DateTime.Now.AddDays(14) : DateTime.Now.AddMinutes(30), model.RememberMe, "Member");
var hashTicket = FormsAuthentication.Encrypt(ticket);
var userCookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashTicket);
Response.Cookies.Add(userCookie);
return RedirectToLocal(returnUrl);
}
ModelState.AddModelError("", "error");
return View(model);
}
FormsAuthenticationTicket userData= "Member"
at last,use the mechanism of Membership Role made in built
结果还是使用了 Membership Role 内置的机制
mvc3 can be read userData

Resources