Search code examples
asp.net-coreasp.net-identityblazor-server-side

ASP.NET Core - use external provider but *keep* Default Identity database


I want the database that comes with the Default Identity provider in ASP.NET Core. However, I'd like users to login exclusively with their Microsoft account.

So at the moment, I have this in my user LoginDisplay.razor file:

<AuthorizeView>
    <Authorized>
        <a href="Identity/Account/Manage">Hello, @context.User.Identity.Name!</a>
        <a href="Identity/Account/LogOut">Log out</a>
    </Authorized>
    <NotAuthorized>
        <a href="Identity/Account/Register">Register</a>
        <a href="Identity/Account/Login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

When the user clicks "Log in" they're taken to the regular login form:

enter image description here

Here they can click on the "Microsoft Account" button. What I would like to do is skip the default login screen and go directly to the Microsoft Account workflow.

How would I do that?

Keeping the identity database offers me a couple of benefits:

  • I plan to add more data to the database - so it's handy if I can refer to accounts that exist in the same database
  • It's possible that I may need to give users access to the site that do not have a Microsoft account

Update

Based on feedback, I've implemented the following:

@inject Data.Services.AntiForgery antiforgery;

<form id="external-account" method="post" class="inline-block form-horizontal" action="/Identity/Account/ExternalLogin?returnUrl=%2F">
    <button type="submit" name="provider" value="microsoft" title="Log in using your Microsoft Account account">Login</button>
    <input name="__RequestVerificationToken" type="hidden" value="@antiforgery.Generate()">
</form>

And here's my utility class that I used to work around the anti-forgery request token (in Blazor):

public class AntiForgery
{
    public IAntiforgery Antiforgery { get; private set; }
    public IHttpContextAccessor Accessor { get; private set; }

    public AntiForgery( IAntiforgery antiforgery, IHttpContextAccessor accessor )
    {
        Antiforgery = antiforgery;
        Accessor = accessor;
    }

    public string Generate()
    {
        // Code stolen from:
        // * https://stackoverflow.com/questions/45254196/asp-net-core-mvc-anti-forgery; and
        // * https://stackoverflow.com/questions/53817373/how-do-i-access-httpcontext-in-server-side-blazor
        return Antiforgery.GetAndStoreTokens( Accessor.HttpContext ).RequestToken;
    }
}

For the utility class to work, the following was added to my Startup file:

services.AddSingleton<AntiForgery>();
services.AddHttpContextAccessor();

Solution

  • Well, you can simply just hide the login form itself, showing only the Microsoft Account button. However, it is not possible to send the user directly into that flow. It requires an initial post, which is going to require action on the user's part, i.e. clicking the button.

    For what it's worth. If you have a "Login" type link, you can code this in the same way as the Microsoft Account button, so that it then initiates the flow when the user clicks "Login". However, you'll still need an actual login page to redirect to for authorization failures, and that would still require an explicit button press there.