Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC 5 OWIN - IsAuthenticated is false on external login (QQ Connect)

I hope someone can help me out with this problem - it's driving me mad! :)

I'm trying to use external login through QQ Connect (OAuth 2.0) using tinysnake's QQ Connect provider: https://github.com/tinysnake/microsoft-owin-security-qq

Everything seems to be going great - I can sign in via my QQ account and I get posted back to my ExternalLoginCallBack-method with the appropriate claims etc. I use these values to sign the user in through the IAuthenticationManager - all goes well. However - when I redirect the user to another page and checks if he's logged in - then I get a false value from the IsAuthenticated value... and I can't read any of the claims I set earlier.

It might be a simple fix - but I just can't see it right now :)

Some code:

AuthConfig:

public static void ConfigureAuthentication(IAppBuilder app)
{
    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

    // Normal cookie sign in
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        AuthenticationMode = AuthenticationMode.Active
    });

    // QQ CONNECT
    app.UseQQConnectAuthentication(
        appId: "XXXXXX",
        appSecret: "XXXXXXXXXXXXXXXXX");
}

AccountController:

//
// POST: /Account/ExternalLogin
[System.Web.Mvc.HttpPost]
[System.Web.Mvc.AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
    // Request a redirect to the external login provider
    return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}

//
// GET: /Account/ExternalLoginCallback
[System.Web.Mvc.AllowAnonymous]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
    var ctx = Request.GetOwinContext();
    var result = ctx.Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalCookie).Result;
    var claims = result.Identity.Claims.ToList();
    var name = claims.First(i => i.Type == "urn:qqconnect:name");

    claims.Add(new Claim(ClaimTypes.AuthenticationMethod, "QQ"));
    claims.Add(new Claim(ClaimTypes.Name, name.Value));

    var ci = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ExternalCookie);
    ctx.Authentication.SignIn(ci);

    // DO OTHER STUFF HERE

    return Redirect("~/");
}

All seems to be going well so far...

HomeController:

public ActionResult Index()
{
    var model = new HomeViewModel();

    var ctx = Request.GetOwinContext();
    if (ctx.Authentication.User.Identity.IsAuthenticated)  // <-- THIS RETURNS FALSE
    {
        var claimsIdentity = User.Identity as ClaimsIdentity;
        model.Name = claimsIdentity.FindFirst(ClaimTypes.Name).Value;
        model.IsAuthenticated = true;
    }

    return View(model);
}

When I check the ctx.Authentication.User.Identity.IsAuthenticated, I get a false value... and I can't retrieve any of the claims either.

Am I missing something?

Any help would be greatly appreciated :)

UPDATE

I got my code working by doing this in my AccountController:

public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
    var ctx = Request.GetOwinContext();
    var result = ctx.Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalCookie).Result;

    if (result.Identity.IsAuthenticated)
    {
        // Signed in successfully
        var claims = result.Identity.Claims.ToList();
        var name = claims.First(i => i.Type == "urn:qqconnect:name");

        //claims.Add(new Claim(ClaimTypes.AuthenticationMethod, "QQ"));
        claims.Add(new Claim(ClaimTypes.Name, name.Value));

        var id = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
        var authenticationManager = ctx.Authentication;
            authenticationManager.SignIn(id);

    }

    return Redirect("~/");
}

But the way I see it - here I'm using the ApplicationCookie and NOT the ExternalCookie for signing in... or am I missing something entirely? This solution works for me - but I'd like to know if this is the right way to be doing this?

like image 524
JBuus Avatar asked Aug 31 '14 16:08

JBuus


People also ask

Why is user identity IsAuthenticated false?

identity. isauthenticated is False when a user is already logged in.

How does request IsAuthenticated work?

Request. IsAuthenticated will then return true . In the case of Forms authentication, the forms authentication module uses the encrypted authentication ticket contained in the authentication cookie to authenticate the user. Once it has done this, it replaces the GenericIdentity in Context.


1 Answers

From my understanding, what you are experiencing is expected. Extremely oversimplifying:

  1. The app gets the external information and uses it to create an external cookie
  2. the external cookie is sent to your app with the assumption that it is just a temporary cookie that will be used to look up any additional local information about the user and then converted to a local [application] cookie

See UseCookieAuthentication vs. UseExternalSignInCookie for a somewhat more thorough breakdown.

like image 88
stephen.vakil Avatar answered Nov 15 '22 05:11

stephen.vakil