1

I'm trying add GitHub authentication to my ASP.NET Core app so that certain users have administrator role. This role I want implement through IdentityRole and users should be stored as IdentityUsers.

I used information from this post as starting point.

I set up authentication through GitHub like this:

services
    .AddAuthentication()
    .AddGitHub(options =>
    {
        options.ClientId = "xxx";
        options.ClientSecret = "xxx";
    }) 

And my Sigin method in controller is here:

public IActionResult SignIn(string provider, string returnUrl = null) =>
            Challenge(new AuthenticationProperties { RedirectUri = returnUrl ?? "/" }, provider);

And I can get GitHub claims via this code:

public IActionResult Index()
{
    var vm = new ProfileViewModel
    {
        Claims = User.Claims,
        Name = User.Identity.Name
    };
    return View(vm);
}

Everything works and everything is fine but it's ClaimsPrincipal not IdentityUser. And I don't understand how can I create new or identify previously stored IdentityUser using this claims. Here are set of articles from Microsoft about using external logins but they used Razor pages and don't provide much info how does it actually bind to IdentityUser.

How can I do the same without using Razor pages?

1 Answer 1

1

For mapping github user to identity user, you need to create the identity user.

For creating IdentityUser without Razor page, you need to construct your request to send the required info to ExternalLoginConfirmation.

[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
    if (remoteError != null)
    {
        ErrorMessage = $"Error from external provider: {remoteError}";
        return RedirectToAction(nameof(Login));
    }
    var info = await _signInManager.GetExternalLoginInfoAsync();
    if (info == null)
    {
        return RedirectToAction(nameof(Login));
    }

    // Sign in the user with this external login provider if the user already has a login.
    var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
    if (result.Succeeded)
    {
        _logger.LogInformation("User logged in with {Name} provider.", info.LoginProvider);
        return RedirectToLocal(returnUrl);
    }
    if (result.IsLockedOut)
    {
        return RedirectToAction(nameof(Lockout));
    }
    else
    {
        // If the user does not have an account, then ask the user to create an account.
        ViewData["ReturnUrl"] = returnUrl;
        ViewData["LoginProvider"] = info.LoginProvider;
        var email = info.Principal.FindFirstValue(ClaimTypes.Email);
        return View("ExternalLogin", new ExternalLoginViewModel { Email = email });
    }
}

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginViewModel model, string returnUrl = null)
{
    if (ModelState.IsValid)
    {
        // Get the information about the user from the external login provider
        var info = await _signInManager.GetExternalLoginInfoAsync();
        if (info == null)
        {
            throw new ApplicationException("Error loading external login information during confirmation.");
        }
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
        var result = await _userManager.CreateAsync(user);
        if (result.Succeeded)
        {
            result = await _userManager.AddLoginAsync(user, info);
            if (result.Succeeded)
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                _logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);
                return RedirectToLocal(returnUrl);
            }
        }
        AddErrors(result);
    }

    ViewData["ReturnUrl"] = returnUrl;
    return View(nameof(ExternalLogin), model);
}
Sign up to request clarification or add additional context in comments.

1 Comment

You just take this code from RazorPages without clarifying how to reach this methods and how to setup Startup...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.