App redirects to Account/AccessDenied on adding Oa

2020-05-25 19:25发布

I've stumbled upon an issue where inconsistently the application redirects the user to Account/AccessDenied/ upon adding a social media authentication to the current logged in user. It seems to work the first time the user is logged in, then by trying to add another authentication method it returns the user to Account/AccessDenied?ReturnUrl=%2Fmanage%2Flinklogincallback.

My guess is that something is going wrong with the [Authorize] attribute, but only the second time I try adding external authentication method.

ManageController

[Authorize]
public class ManageController : Controller
{
    //
    // POST: /Manage/LinkLogin
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult LinkLogin(string provider)
    {
        // Request a redirect to the external login provider to link a login for the current user
        var redirectUrl = Url.Action("LinkLoginCallback", "Manage");
        var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User));
        return Challenge(properties, provider);
    }

    //
    // GET: /Manage/LinkLoginCallback
    [HttpGet]
    public async Task<ActionResult> LinkLoginCallback()
    {
        var user = await GetCurrentUserAsync();
        if (user == null)
        {
            return View("Error");
        }
        var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user));
        if (info == null)
        {
            return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error });
        }
        var result = await _userManager.AddLoginAsync(user, info);
        var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error;
        return RedirectToAction(nameof(ManageLogins), new { Message = message });
    }
}

Could it be the order of how startup.cs is arranged?

This is the request/response

enter image description here

5条回答
家丑人穷心不美
2楼-- · 2020-05-25 19:53

workaround helped me until it’s resolved by asp.net team

    // GET: /Account/AccessDenied
    [HttpGet]
    [AllowAnonymous]
    public IActionResult AccessDenied(string returnUrl = null)
    {
        // workaround
        if (Request.Cookies["Identity.External"] != null)
        {
            return RedirectToAction(nameof(ExternalLoginCallback), returnUrl);
        }
        return RedirectToAction(nameof(Login));

    }
查看更多
祖国的老花朵
3楼-- · 2020-05-25 20:01

I too faced the same issue. I was using the code from IdentityServer4 QuickStart sample from here

        app.UseGoogleAuthentication(new GoogleOptions
        {
            AuthenticationScheme = "Google",
            DisplayName = "Google",
            SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme,

            ClientId = "xxx.apps.googleusercontent.com",
            ClientSecret = "xxxx-Xxxxxxx"
        });

I had to change the code to the following to fix the issue.

        var CookieScheme= app.ApplicationServices.GetRequiredService<IOptions<IdentityOptions>>().Value.Cookies.ExternalCookieAuthenticationScheme;

        app.UseGoogleAuthentication(new GoogleOptions
        {
            AuthenticationScheme = "Google",
            DisplayName = "Google",
            SignInScheme = CookieScheme,

            ClientId = "xxx.apps.googleusercontent.com",
            ClientSecret = "xxxx-Xxxxxxx"
        });

Instead of just using the constant 'external' from the IdentityServerConstants.ExternalAUthenticationScheme I had to obtain the scheme used to identify external authentication cookies from the cookie options of the current identity system used by the app. That is what fixed the issue for me.

查看更多
男人必须洒脱
4楼-- · 2020-05-25 20:01

If you've set config.SignIn.RequireConfirmedEmail = true in Startup.cs and the EmailConfirmed field is false for an externally authenticated user (e.g. Facebook login), on subsequent logins, you'll be directed to the Account/AccessDenied/ action method.

查看更多
smile是对你的礼貌
5楼-- · 2020-05-25 20:12

I've got confirmed by aspnet team working on Security repo that this is a bug (see this issue) and resolved until next release. A temporary workaround is to set a cookie named

Identity.External

to null, which is created upon adding external login to your account.

if (Request.Cookies["Identity.External"] != null)
{
     Response.Cookies.Delete("Identity.External"); 
}
查看更多
smile是对你的礼貌
6楼-- · 2020-05-25 20:13

@Rovdjuret's workaround helped me until it’s resolved by asp.net team. Here is my controller Login action:

public IActionResult Login(string returnUrl = null)
{
    if (_signInManager.IsSignedIn(User))
    {
        // redirect to user profile page
        return RedirectToAction(nameof(HomeFileController.Index), "HomeFile");                
    }
    else
    {
        // clear Identity.External cookie
        if (Request.Cookies["Identity.External"] != null)
        {
            Response.Cookies.Delete("Identity.External");
        }
        return View(new LoginViewModel{ ReturnUrl = returnUrl, RememberMe = true });
    }
}

Update: In the latest version (as of May 2017) the cookies have prefix ".AspNetCore.". So cookie name should be ".AspNetCore.Identity.External"

查看更多
登录 后发表回答