ASP.Net MVC 4 Generic Principal Difficulties

2019-03-09 20:41发布

I am developing an ASP.Net MVC 4 web application. Previously my MVC applications have been developed using MVC 3 and with this new MVC 4 application I have just copied/ reused my authentication and authorisation code from previous applications.

When a user logs into my site I do the following

Account Controller

public ActionResult Login(LoginModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        User user = _userService.GetUser(model.Email.Trim());

        //Create Pipe Delimited string to store UserID and Role(s)
        var userData = user.ApplicantID.ToString();

        foreach (var role in user.UserRoles)
        {
            userData = userData + "|" + role.description;
        }

        _formAuthService.SignIn(user.ApplicantFName, false, userData);

        return RedirectToAction("Index", "Portfolio");
        }

        return View(model);
    }

FormsAuthenticationService

public class FormsAuthenticationService : IFormsAuthenticationService
{
    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);
    }
}

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 code works well in my previous MVC 3 applications, but in this MVC 4 application, inside the Razor View, the following code does not seem to be accessing the IsInRole property to perform the role check

@if (HttpContext.Current.User.IsInRole("Applicant"))
{
    <p>text</text>
}

Again, this worked perfectly in my MVC 3 applications.

Does anyone have any ideas or suggestions as to why this won't work with my MVC 4 application?

Any help is much appreciated.

Thanks.

Extra Info

My MVC 4 application is using .Net Framework 4.0

The screenshot below shows my Generic Principal which is assigned to Context.User. You can see that for this User, the m_roles contains two strings, the UserID (100170) and their Role(Applicant). But for some reason, The IsInRoles cannot be accessed or seen in my MVC 4 Razor View, however, it could in my identical MVC 3 Razor View. enter image description here

3条回答
孤傲高冷的网名
2楼-- · 2019-03-09 21:02

In MVC 4 HttpContext.Current.User is not exposed so you can't use it. What i did was create a custom BaseViewPage and added following code in it.

    public abstract class BaseViewPage : WebViewPage
    {
        public virtual new Principal User
        {
            get { return base.User as Principal; }
        }
    }

    public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
    {
        public virtual new Principal User
        {
            get { return base.User as Principal; }
        }
    }

And then make following changes to system.web.webPages.razor/pages section your web.config in Views folder.

<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="WebApp.Views.BaseViewPage">
  <namespaces>
    ...
  </namespaces>
</pages>

Hope this solves your problem.

查看更多
贪生不怕死
3楼-- · 2019-03-09 21:04

Folks

I finally resolved this issue. It appears by default the SimpleMembershipProvider is enabled when you create a new ASP.NET MVC 4 application. I did not want to use the SimpleMembershipProvider on this occasion, however, I needed to disable it in my web config with the following line

<appSettings>
    <add key="enableSimpleMembership" value="false" />
</appSettings>

My call to User.IsInRole works great now.

Hope this helps someone else.

查看更多
smile是对你的礼貌
4楼-- · 2019-03-09 21:27

In MVC 4 you can access the User from the WebPageRenderingBase, so inside razor syntax you have direct access to the User instance:

@if (Request.IsAuthenticated && User.IsInRole("Applicant"))
{
    <p>text</p>
}

I see that you are creating a FormsAuthenticationTicket and an HttpCookie manually. The FormsAuthentication class would do this for you using SetAuthCookie(string, bool[, string]). In this sense your auth service can be reduced to:

public class FormsAuthenticationService : IFormsAuthenticationService
{
    public void SignIn(string userName, bool createPersistentCookie, string UserData)
    {
        if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");

        FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
    }
}

It turns out you also need to change Application_AuthenticateRequest to Application_OnPostAuthenticateRequest:

protected void Application_OnPostAuthenticateRequest(Object sender, EventArgs e)
查看更多
登录 后发表回答