Error trying to get authenticate with google in ASP.NET Core 3.1 No authentication handler is registered

Viewed 511

The Error authentication Error with Google

This is my startup class

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        // Demand authentication in the whole application
        services.AddControllersWithViews(o => o.Filters.Add(new AuthorizeFilter()));

        services.AddScoped<IConferenceRepository, ConferenceRepository>();
        services.AddScoped<IProposalRepository, ProposalRepository>();
        services.AddScoped<IAttendeeRepository, AttendeeRepository>();
        services.AddScoped<IUserRepository, UserRepository>();

        services.AddDbContext<ConfArchDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                assembly => 
                   assembly.MigrationsAssembly(typeof(ConfArchDbContext).Assembly.FullName)));

        services
           .AddAuthentication(options =>
           {
               options.DefaultScheme = 
                    CookieAuthenticationDefaults.AuthenticationScheme;
               options.DefaultChallengeScheme = 
             GoogleDefaults.AuthenticationScheme;
           })
           .AddCookie(options =>
           {
               options.Cookie.IsEssential = true;
               //options.Cookie.SameSite = SameSiteMode.None;
           })
           .AddGoogle(options =>
           {                   
               options.SignInScheme = 
               CookieAuthenticationDefaults.AuthenticationScheme;
               options.ClientId = 
                Configuration["Authentication:Google:ClientId"];
               options.ClientSecret = 
              Configuration["Authentication:Google:ClientSecret"];
           });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        //app.UseIdentity();
        // app.UseAuthentication();           

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseCookiePolicy();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {                   
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Conference}/{action=Index}/{id?}");
        });
    }
}

this is my controller, the error is thrown in the line: var result = await HttpContext.AuthenticateAsync(

public class AccountController : Controller
{
    private readonly IUserRepository userRepository;

    public AccountController(IUserRepository userRepository)
    {
        this.userRepository = userRepository;
    }

    // This method must be anonymous to allow access to not logged users
    [AllowAnonymous]
    public IActionResult Login(string returnUrl = "/")
    {
        return View(new LoginModel { ReturnUrl = returnUrl });
    }

    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> Login(LoginModel model)
    {  
        // Looking for user in local repository in the class userrepository
        var user = userRepository.GetByUsernameAndPassword(model.Username, model.Password);
        if (user == null)
            return Unauthorized();

        // Data of the user, claims class is used to represent the data user
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.Name),
            new Claim(ClaimTypes.Role, user.Role),
            new Claim("FavoriteColor", user.FavoriteColor)
        };

        // Object to save in Identity object type ClaimsIdentity
        var identity = new ClaimsIdentity(claims,
            CookieAuthenticationDefaults.AuthenticationScheme);
        // Create claims principal object with the Identity
        var principal = new ClaimsPrincipal(identity);

        await HttpContext.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme,
            principal,
            new AuthenticationProperties { IsPersistent = 
                 model.RememberLogin,                     
                 ExpiresUtc= DateTime.UtcNow.AddMinutes(10)
                                         });
        return LocalRedirect(model.ReturnUrl);
    }

    [AllowAnonymous]
    public IActionResult LoginWithGoogle(string returnUrl = "/")
    {
        var props = new AuthenticationProperties
        {
            RedirectUri = Url.Action("GoogleLoginCallback"),
            Items =
            {
                { "returnUrl", returnUrl }
            }
        };
        return Challenge(props, GoogleDefaults.AuthenticationScheme);
    }

    [AllowAnonymous]
    public async Task<IActionResult> GoogleLoginCallback()
    {
        // read google identity from the temporary cookie
        var result = await HttpContext.AuthenticateAsync(
            ExternalAuthenticationDefaults.AuthenticationScheme);

        var externalClaims = result.Principal.Claims.ToList();

        var subjectIdClaim = externalClaims.FirstOrDefault(
            x => x.Type == ClaimTypes.NameIdentifier);
        var subjectValue = subjectIdClaim.Value;

        var user = userRepository.GetByGoogleId(subjectValue);

        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.Name),
            new Claim(ClaimTypes.Role, user.Role),
            new Claim("FavoriteColor", user.FavoriteColor)
        };

        var identity = new ClaimsIdentity(claims,
            CookieAuthenticationDefaults.AuthenticationScheme);
        var principal = new ClaimsPrincipal(identity);

        // delete temporary cookie used during google authentication
        await HttpContext.SignOutAsync(
            ExternalAuthenticationDefaults.AuthenticationScheme);

        await HttpContext.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme, principal);

        return LocalRedirect(result.Properties.Items["returnUrl"]);
    }

    // Action to logout
    public async Task<IActionResult> Logout()
    {
        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        return Redirect("/");
    }
}
1 Answers

I figure out the answer, the in the configure services code should be so:

// Demand authentication in the whole application
services.AddControllersWithViews(o => o.Filters.Add(new 
AuthorizeFilter()));

services.AddScoped<IConferenceRepository, ConferenceRepository>();
services.AddScoped<IProposalRepository, ProposalRepository>();
services.AddScoped<IAttendeeRepository, AttendeeRepository>();
services.AddScoped<IUserRepository, UserRepository>();

services.AddDbContext<ConfArchDbContext>(options =>


 options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
        assembly => 
 assembly.MigrationsAssembly(typeof(ConfArchDbContext).Assembly.FullName)));

services.AddAuthentication(o => {
    o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    //o.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
})
.AddCookie()
.AddCookie(ExternalAuthenticationDefaults.AuthenticationScheme)
.AddGoogle(o =>
{   // ClienteId and Secret to authenticate the user from Google          
    o.SignInScheme = 
        ExternalAuthenticationDefaults.AuthenticationScheme;
    o.ClientId = Configuration["Authentication:Google:ClientId"];
    o.ClientSecret = 
       Configuration["Authentication:Google:ClientSecret"];
});
Related