Customize External Identity Login on Custom Buttons

0

I'm trying to implement ExternalLogin in a web application with Facebook and Google, and the login screen is customized. As I'm using DDD and CQRS, I have the Identity decoupled from the asp.net core 2.1 project. I need to integrate the custom buttons I created in my view into Identity so that it treats everything to me as it is used in the standard ASP.NET project. Here are the codes:

View Login

<div class="container mt--8 pb-5">
  <div class="row justify-content-center">
    <div class="col-lg-5 col-md-7">
      <div class="card bg-secondary shadow border-0">
        <div class="card-header bg-transparent pb-5">
          <div class="text-muted text-center mt-2 mb-3"><small>Entrar com</small></div>
          <div class="btn-wrapper text-center">
            <form id="external-account" method="post">
              <a href="#" class="btn btn-neutral btn-icon">
                <span class="btn-inner--icon"><img src="~/assets/img/icons/common/facebook.svg"></span>
                <span class="btn-inner--text">Facebook</span>
              </a>
              <button class="btn btn-neutral btn-icon" name="provider">
                                <span class="btn-inner--icon"><img src="~/assets/img/icons/common/google.svg"></span>
                                <span class="btn-inner--text">Google</span>
                            </button>
            </form>
          </div>
        </div>
        <div class="card-body px-lg-5 py-lg-5">
          <div class="text-center text-muted mb-4">
            <small>Ou entre com suas credenciais</small>
          </div>
          <form asp-route-returnUrl="@ViewData[" ReturnUrl "]" method="post" role="form" id="login-form">
            <div class="form-group mb-3">
              <div class="input-group input-group-alternative">
                <div class="input-group-prepend">
                  <span class="input-group-text"><i class="ni ni-email-83"></i></span>
                </div>
                <input asp-for="Email" class="form-control" placeholder="Email" type="email" name="email">
              </div>
            </div>
            <div class="form-group">
              <div class="input-group input-group-alternative">
                <div class="input-group-prepend">
                  <span class="input-group-text"><i class="ni ni-lock-circle-open"></i></span>
                </div>
                <input asp-for="Password" class="form-control" placeholder="Senha" type="password" name="password">
              </div>
            </div>
            <div class="custom-control custom-control-alternative custom-checkbox">
              <input asp-for="RememberMe" class="custom-control-input" id=" customCheckLogin" type="checkbox" name="remember-me">
              <label class="custom-control-label" for=" customCheckLogin">
                                <span class="text-muted">Lembrar-me</span>
                            </label>
            </div>
            <div class="text-center">
              <button type="submit" class="btn btn-primary my-4" id="btn-login-submit">Entrar</button>
            </div>
          </form>
        </div>
      </div>
      <div class="row mt-3">
        <div class="col-6">
          <a asp-action="ForgotPassword" asp-controller="Account" class="text-light"><small>Esqueceu a senha?</small></a>
        </div>
        <div class="col-6 text-right">
          <a asp-action="Register" asp-controller="Account" class="text-light"><small>Registrar usuário</small></a>
        </div>
      </div>
    </div>
  </div>
</div>

Class Startup.cs

public void ConfigureServices(IServiceCollection services)
{
   ....
                          
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(o => 
                { 
                  o.LoginPath = new PathString("/login");
                  o.AccessDeniedPath = new PathString("/home/access-denied");
                })
                .AddFacebook(o =>
                {
                 o.AppId = Configuration["Authentication:Facebook:AppId"];
                 o.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
                 o.CallbackPath = new PathString("/signin-facebook");
                 o.AuthorizationEndpoint = FacebookDefaults.AuthorizationEndpoint;
                 o.TokenEndpoint = FacebookDefaults.TokenEndpoint;
                 o.SaveTokens = true;
                })
                .AddGoogle(googleOptions =>
                {
                 googleOptions.ClientId = Configuration["Authentication:Google:ClientId"];
                 googleOptions.ClientSecret = Configuration["Authentication:Google:ClientSecret"];
                 googleOptions.CallbackPath = new PathString("/signin-google");
                 googleOptions.AuthorizationEndpoint = GoogleDefaults.AuthorizationEndpoint;
                 googleOptions.TokenEndpoint = GoogleDefaults.TokenEndpoint;
                 googleOptions.SaveTokens = true;
                });           
}

Up to everything following the same steps of countless examples on the internet. The question is: how can I in View associate with my buttons the call for all ExternalLogin to work?

    
asked by anonymous 31.12.2018 / 04:56

1 answer

1

Hello, You first need to associate the schema with each button and each submit to an action and as a result generate a Challenge for the specific provider (google, facebook etc).

Button Example: (I'm using Traditional Razor)

      <a class="btn btn-default"
                                   asp-controller="External"
                                   asp-action="Challenge"
                                   asp-route-provider="@provider.AuthenticationScheme"
                                   asp-route-returnUrl="@Model.ReturnUrl">
                                    @provider.DisplayName
                                </a>

The Array of configured Providers can be obtained in the controller using and injecting the SignInManager like this:

private readonly SignInManager<IdentityUser> _signInManager;
public IList<AuthenticationScheme> ExternalLogins { get; set; }   

public ConstrutorDoController(SignInManager<IdentityUser> signInManager)
{
    _signInManager = signInManager;
}

In your Get you can pass through the model to the page the array obtained from the schemas configured in the startup like this:

 ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();

An example of the ExternalLoginController of the button action Challenge:

  [HttpGet]
        public  Task<IActionResult> Challenge(string provider, string returnUrl)
        {

            // start challenge and roundtrip the return URL and scheme 
            var props = new AuthenticationProperties
            {
                RedirectUri = Url.Action(nameof(Callback)),
                Items =
                {
                    { "returnUrl", returnUrl },
                    { "scheme", provider },
                }
            };

            return Challenge(props, provider);

        }

And the callback reported in the above properties via returnUrl:

  [HttpGet]
        public async Task<IActionResult> Callback()

 var info = await _signInManager.GetExternalLoginInfoAsync();
            if (info == null)
            {
                ErrorMessage = "Error loading external login information.";
                return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
            }
// Codigo omitido, faça sua logica aqui, mande para o cadastro ou faça o login...
        {
}

I hope this helps, the code is not complete with all exception treatments, but I believe it will give you a north.

    
31.12.2018 / 14:06