CORS Issue with Dotnet 5 Web Api



我有一个带有Angular2+前端的dotnet 5 web API,我是从以前的3.1 MVC版本的应用程序中构建的。我在寻求与雅虎进行身份验证时遇到了一个与MVC版本没有的CORS问题。我得到的错误是:

"访问位于"的XMLHttpRequesthttps://api.login.yahoo.com...'(重定向自'https://localhost:5003/api/draft/yahooauth/'(来源'https://localhost:5003'已被CORS策略阻止:对飞行前请求的响应未通过访问控制检查:请求的资源上不存在"access control Allow Origin"标头">

我的API控制器:

[EnableCors("MyPolicy")]
[HttpPost("yahooauth")]
public void YahooAuth()
{
string leftUrl = string.Format("{0}://{1}", HttpContext.Request.Scheme, HttpContext.Request.Host);
string returnUrl = $"{leftUrl}/api/draft/yahooexchange";
string id = configuration["YahooClientId"];
string secret = configuration["YahooClientSecret"];
string url = $"https://api.login.yahoo.com/oauth2/request_auth?client_id={id}&redirect_uri={returnUrl}&response_type=code&language=en-us";
Response.Redirect(url);            
}
[HttpGet("yahooexchange/{code}")]
public IActionResult yahooexchange(string code)
{
// Code that is supposed to be triggered with returnUrl from Yahoo
}

Startup.cs:

public class Startup
{
public Startup(IConfiguration configuration) => Configuration = configuration;
public IConfiguration Configuration { get; }
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential 
// cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
// requires using Microsoft.AspNetCore.Http;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<IdentityDbCxt>(options => options.UseSqlServer(Configuration.GetConnectionString("IdentityDb")));
services.AddDbContext<DraftContext>(options => options.UseSqlServer(Configuration.GetConnectionString("FSDraftDb")));
services.AddIdentity<AppUser, IdentityRole>(opts =>
{
opts.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<IdentityDbCxt>()
.AddDefaultTokenProviders();
services.AddTransient<IEmailSender, EmailSender>();
services.AddTransient<IAPICall, APICall>();
services.AddTransient<IDraftService, DraftService>();
services.AddCors(options =>
{
options.AddPolicy("MyPolicy",
builder =>
{
builder.WithOrigins("*")
.AllowAnyHeader()
.AllowAnyMethod();
});
});

services.AddMvc()
.AddRazorRuntimeCompilation();
services.AddMemoryCache();
services.AddSession();
services.AddSingleton<IHtmlSanitizer, HtmlSanitizer>();
services.AddControllersWithViews(/*options =>
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute())*/);

services.AddRazorPages();
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1",
new OpenApiInfo { Title = "API", Version = "v1" });
});
services
.AddControllers()
.AddNewtonsoftJson();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostEnvironment env, IServiceProvider services)
{
//app.UseMiddleware<GCMiddleware>();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}

app.UseStatusCodePages();
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseSession();
app.UseRouting();
app.UseCors();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}");
endpoints.MapControllerRoute(
name: "angular_fallback",
pattern: "{target:regex(draft|data|keeper|adminapi|admin`):nonfile}/{*catchall}",
defaults: new { controller = "Home", action = "Index" });
endpoints.MapRazorPages();
});
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "API");
});
app.UseSpa(spa =>
{
string strategy = Configuration.GetValue<string>("DevTools:ConnectionStrategy");
if (strategy == "proxy")
{
spa.UseProxyToSpaDevelopmentServer("http://127.0.0.1:4200");
}
else if (strategy == "managed")
{
spa.Options.SourcePath = "../ClientApp";
spa.UseAngularCliServer("start");
}
});

}
}

我已经查看了一些来源,包括这里一个非常有希望的帖子,但这并没有解决我的问题:在dotnet core 3.1 中,CORS对飞行前的响应问题

如果有帮助的话,我希望做第2步:https://developer.yahoo.com/oauth2/guide/flows_authcode/

编辑:这是我使用的关于CORS的文档:https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-5.0#属性

尝试使用此语法并将AddCors移到ConfigureServices的顶部。为UseRouting指定名称。

services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
.......
....
app.UseRouting();
app.UseCors("MyPolicy");
app.UseAuthentication();
app.UseAuthorization();
.....

因此,我最终找到了一个解决方法,并创建了一个新的MVC控制器,因为我以前的MVC应用程序运行良好。

此外,我意识到我还没有为新的返回URI更新我的雅虎开发者应用程序。这并没有解决我的CORS问题,但它阻止了它正常工作。

Angular中的代码转到新控制器。

window.location.href = "https://localhost:5003/yahoo/index";

我的MVC控制器:

public class YahooController : Controller
{
private IAPICall apiCall;
public YahooController(IAPICall aCall)
{
apiCall = aCall;
}
// getting session data on player values
private DraftService GetDS()
{
DraftService draftService = HttpContext.Session.GetJson<DraftService>("DraftService") ?? new DraftService();
return draftService;
}
// saving session data on player values
private void SaveDS(DraftService ds)
{
HttpContext.Session.SetJson("DraftService", ds);
}
[HttpGet]
public void Index()
{
string returnUrl = Url.Action("yahooexchange",
"yahoo", new
{
},
protocol: HttpContext.Request.Scheme);

string url = apiCall.YahooAuthUrl(returnUrl);
Response.Redirect(url);
}
public void yahooexchange(string code)
{
string content = apiCall.YahooGetToken(code);
var jContent = JsonConvert.DeserializeObject<JObject>(content);

string accessToken = jContent.GetValue("access_token").ToString();
string refreshToken = jContent.GetValue("refresh_token").ToString();
string leftUrl = string.Format("{0}://{1}", HttpContext.Request.Scheme, HttpContext.Request.Host);
DraftService ds = GetDS();

ds.YahooAccessToken = accessToken;
ds.YahooRefreshToken = refreshToken;
SaveDS(ds);
string url = leftUrl + "/draft/" + ds.DraftId;
Response.Redirect(url);
}
}

最新更新