0

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();
Mitkins
  • 4,031
  • 3
  • 40
  • 77

2 Answers2

1

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.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • I wouldn't mind playing around with that to see what it looks like in practice. I'm also interested in learning how to write the code to create the "Login" type button - just to understand how that might work. Is there any documentation that covers how to do this? I'm having trouble finding it! – Mitkins Aug 29 '19 at 23:21
  • It's the same code that's currently generating the Microsoft Account button. You just literally change the button text to Login and maybe style it to look like a link instead of a button. – Chris Pratt Aug 29 '19 at 23:41
  • Thanks! I've added a little bit of code to my question to show what I did. I'll test it some more to see if it can achieve what I want – Mitkins Aug 30 '19 at 06:25
1

You could directly pass the provider name Microsoft to your external login function using asp-route-provider.

For asp.net core 2.2+, Identity is scaffolded into identity area with Razor Pages.

1.Login link.

<a asp-area="Identity" asp-page="/Account/ExternalLogin" asp-page-handler="TestExternal" asp-route-provider="Microsoft">Log in</a>

2.ExternalLogin.cshtml.cs

public IActionResult OnGetTestExternalAsync(string provider, string returnUrl = null)
    {
        var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
        var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
        return new ChallengeResult(provider, properties);
    }

3.Startup.cs

services.AddAuthentication().AddMicrosoftAccount(microsoftOptions =>
{
    //use your own Id and secret
    microsoftOptions.ClientId = Configuration["Authentication:Microsoft:ClientId"];
    microsoftOptions.ClientSecret = Configuration["Authentication:Microsoft:ClientSecret"];
});
Ryan
  • 19,118
  • 10
  • 37
  • 53