3

I'm trying to implement a single-page app. I carried over some of my working code from another project (MVC4) to implement authentication. Right now I see cookies being set, but WebSecurity / User.Identity do not seem to be working for some reason. After logging in, subsequent requests never validate as authenticated, either via WebSecurity.IsAuthenticated, or User.Identity.IsAuthenticated. Does anyone know why this is happening?

Controller code:

public class AccountController : ApiController {

    private readonly UserService _userService;

    public AccountController() {}

    public AccountController(UserService userService) {
        _userService = userService;
    }

    [AllowAnonymous]
    [HttpGet]
    [Route("api/authpayload")]
    // This gets called when the app loads.  Always, User.Identity.IsAuthenticated is false. 
    public HttpResponseMessage AuthPayload() {
        var payload = new AuthPayloadDto();
        try {
            var userId = WebSecurity.GetUserId(User.Identity.Name);
            if (User.Identity.IsAuthenticated && userId > 0) {
                payload.Username = User.Identity.Name;
            } else {
                LogOut();
                payload.IsAuthenticated = false;
            }
            return Request.CreateResponse(HttpStatusCode.OK, payload);
        } catch (Exception e) {
            return Request.CreateResponse(HttpStatusCode.InternalServerError, e);
        }
    }

    [HttpPost]
    [Route("api/login")]
    [AllowAnonymous]
    public HttpResponseMessage LogIn(LoginModel model) {
        if (!ModelState.IsValid)
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
        try {
            if (WebSecurity.IsAuthenticated)
                return Request.CreateResponse(HttpStatusCode.Conflict, "already logged in.");
            if (!WebSecurity.UserExists(model.Username))
                return Request.CreateResponse(HttpStatusCode.Conflict, "User does not exist.");
            if (WebSecurity.Login(model.Username, model.Password, persistCookie: model.RememberMe)) {
                // This code always gets hit when I log in, no problems.  I see a new cookie get sent down as well, using Chrome debugger.
                var payload = new AuthPayloadDto();
                return Request.CreateResponse(HttpStatusCode.OK, payload);
            }
            LogOut();
            return Request.CreateResponse(HttpStatusCode.Forbidden, "Login Failed.");
        } catch (Exception e) {
            return Request.CreateResponse(HttpStatusCode.InternalServerError, e);
        }
    }

Web.config:

<system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
    <authentication mode="Forms">
      <forms loginUrl="~/" timeout="2880" />
    </authentication>
    <roleManager enabled="true" defaultProvider="simple">
      <providers>
        <clear />
        <add name="simple" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
      </providers>
    </roleManager>
    <membership defaultProvider="simple">
      <providers>
        <clear />
        <add name="simple" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
      </providers>
    </membership>
    <!--
            If you are deploying to a cloud environment that has multiple web server instances,
            you should change session state mode from "InProc" to "Custom". In addition,
            change the connection string named "DefaultConnection" to connect to an instance
            of SQL Server (including SQL Azure and SQL  Compact) instead of to SQL Server Express.
      -->
    <sessionState mode="InProc" customProvider="DefaultSessionProvider">
      <providers>
        <add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" />
      </providers>
    </sessionState>

  </system.web>

The cookie that gets sent after login is not expired, and it does get sent back on subsequent requests, but IsAuthenticated is always false. What am I doing wrong?

Update:

I updated my web.config to the following to get everything working:

<system.web>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
    <roleManager enabled="true" defaultProvider="SimpleRoleProvider">
      <providers>
        <clear />
        <add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
      </providers>
    </roleManager>
    <membership defaultProvider="SimpleMembershipProvider">
      <providers>
        <clear />
        <add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
      </providers>
    </membership>
  </system.web>

But I'd like to leave this open in case anyone has an explanation of why this works; I'm pretty lost.

RobVious
  • 12,685
  • 25
  • 99
  • 181
  • From my personal experience, I was never able to get authentication to work through MVC's Web API (using MVC 4 and 5). If a user signs-in through MVC's social logins, then I am able to check if the current user is signed in or not through the Web API. But trying to actually sign-in the user has always been a challenge. There are other third party authentication services out there that work with MVC to solve this issue (like auth0.com). – ahmed.eltawil Jan 11 '15 at 04:53
  • did you resolve you problem? I am facing the same problem too..It verifies the user successfully but isauthenticated is still false. – UmarKashmiri Jan 28 '15 at 10:49

1 Answers1

0

In my current mvc 4 project with mssql, its a simple one i so I just wanted very simple memmbership provider I disabled InitializeSimpleMembershipAttribute

by

[Authorize]
//[InitializeSimpleMembership]
public partial class AccountController : Controller

and added this code to global.asax under Application_Start

WebSecurity.InitializeDatabaseConnection(
             connectionStringName: "DefaultConnection",
             userTableName: "UserProfile",
             userIdColumn: "UserID",
             userNameColumn: "UserName",
             autoCreateTables: true);

in my sql database the application created some tables on of them was Roles and UserInRoles just added the roles I needed like Admin, customer, etc... and I restrict the access to some Controllers or Actions by adding this code

[Authorize(Roles = "Admin")]
public class MessagesController : Controller
Shlomi.y27
  • 41
  • 5