Reputation: 15
Context: Im Developing a WEB API in .NET 8 with Facebook Authentication using .net 8 identity core
Desired Behavior: I need the api to expose a Get endpoint and start Facebook Authentication flow when the endpoint is hit.
Problem
Conclusion I dont know if this is the flow expected for a .NET API, but it seemed to have issues setting my response. Thanks For your time, ive been looking for this on the web and i dont seemed to find an answer.
Program.cs
using emps.DTO;
using emps.Models;
using emps.Repository;
using emps.Services;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Facebook;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Filters;
var builder = WebApplication.CreateBuilder(args);
// CORS CONFIGURATION
builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
builder.Services.AddCors(options => {
options.AddPolicy("debug", cors => {
cors.AllowAnyMethod();
cors.AllowCredentials();
cors.AllowAnyHeader();
cors.WithOrigins("https://localhost:3000");
});
});
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection(""));
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
//IDENTITY CONFIGURATION
builder.Services.Configure<IdentityOptions>(options =>
{
options.User.RequireUniqueEmail = true;
options.Password.RequireNonAlphanumeric = false;
options.Lockout.AllowedForNewUsers = true;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
});
builder.Services.AddAuthentication(options =>{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = FacebookDefaults.AuthenticationScheme;
}).AddFacebook(options => {
options.AppId = builder.Configuration["appId"] ?? "";
options.AppSecret = builder.Configuration["appSecret"] ?? "";
options.CallbackPath = "/api/Auth/cb";
options.Scope.Add("pages_manage_engagement");
options.Scope.Add("pages_manage_posts");
options.Scope.Add("pages_read_engagement");
options.Scope.Add("publish_video");
options.Scope.Add("public_profile");
options.Scope.Add("email");
options.Fields.Add("email");
options.Fields.Add("name");
});
//COOKIE CONFIGURATION
builder.Services.ConfigureApplicationCookie(options => {
options.Cookie.Name = "mytoken";
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
options.SlidingExpiration = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Lax;
});
builder.Services.AddIdentityApiEndpoints<User>().AddEntityFrameworkStores<IdentityContext>();
//SWAGGER Configuration
builder.Services.AddSwaggerGen(options =>
{
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Name = "Authorization",
Type = SecuritySchemeType.ApiKey
});
options.OperationFilter<SecurityRequirementsOperationFilter>();
});
// DB Context
builder.Services.AddDbContext<IdentityContext>(options => {
options.UseSqlServer(builder.Configuration.GetConnectionString("defaultConnection"));
});
//Repositorios
builder.Services.AddScoped<PostRepository>();
builder.Services.AddScoped<UsersRepository>();
//Servicios
builder.Services.AddScoped<PostService>();
builder.Services.AddScoped<UsersService>();
//builder.Services.AddHttpClient();
builder.Services.AddScoped<FacebookService>();
builder.Services.AddAuthorization();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapIdentityApi<User>();
app.UseCors((options) => {
options.AllowAnyHeader();
options.AllowCredentials();
options.AllowAnyMethod();
options.AllowAnyHeader();
options.SetIsOriginAllowedToAllowWildcardSubdomains();
options.WithOrigins(["https://localhost:3000", "https://web.facebook.com"]);
});
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Controller Routes
public async Task< IActionResult> FacebookLogin() {
var properties = this.SignInManager.ConfigureExternalAuthenticationProperties("Facebook", null);
properties.RedirectUri = Url.Action("FacebookCb", "Auth");
return Challenge(properties,"Facebook");
}
[HttpGet("cb")]
public async Task<IActionResult> FacebookCb(string code)
{
Console.WriteLine(code);
var response = await this.SignInManager.GetExternalLoginInfoAsync();
if (response != null)
{
var email = response.Principal.FindFirst(x => x.Type == ClaimTypes.Email);
var username = response.Principal.FindFirst(x => x.Type == ClaimTypes.Name);
if (email != null && username != null)
{
User userData = new User { Email = email.Value, UserName = username.Value };
await SignInManager.SignInAsync(userData, true);
var myUser = await this._service.GetUser(email.Value);
if (myUser != null)
{
if (response != null && response.AuthenticationTokens != null)
{
var token = response.AuthenticationTokens.FirstOrDefault(e => e.Name == "access_token");
}
}
}
}
return NoContent();
}
System.InvalidOperationException: StatusCode cannot be set because the response has already started.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAlreadyStartedException(String value)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode(Int32 value)
at Microsoft.AspNetCore.Http.DefaultHttpResponse.Redirect(String location, Boolean permanent)
at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
at Microsoft.WebTools.BrowserLink.Net.BrowserLinkMiddleware.InvokeAsync(HttpContext context)
at Microsoft.AspNetCore.Watch.BrowserRefresh.BrowserRefreshMiddleware.InvokeAsync(HttpContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
Thanks For your time I hope my question is clear enoght
Upvotes: 0
Views: 63