Response to preflight request doesn't pass access control check: It does not have HTTP ok status. GET working POST PUT DELETE not working

那年仲夏 提交于 2020-12-06 06:43:23

问题


Greetings

I have one web application with following architecture: Web api: ASP.net core 2.1 (Windows Authentication) UI: angular 8

UI is able to get data but unable to send data. I mean GET method is working fine but POST, PUT, DELETE options are not working . And all the methods are working using POSTMAN.

ERROR is: Access to XMLHttpRequest at 'http://xx.xxx.xxx.xx:xxyy/xxx/xxxxxx/Method' from origin 'http://localhost:xxxx' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

Any help will be appreciated .

Thanks in advance :)


回答1:


This is what i use and it should work i hope for your case.

My startup.cs ConfigureServices() decorated with:

services.AddCors(feature =>
                feature.AddPolicy(
                    "CorsPolicy",
                    apiPolicy => apiPolicy
                                    //.AllowAnyOrigin()
                                    //.WithOrigins("http://localhost:4200")
                                    .AllowAnyHeader()
                                    .AllowAnyMethod()
                                    .SetIsOriginAllowed(host => true)
                                    .AllowCredentials()
                                ));

And, Configure() method with:

app.UseCors("CorsPolicy");

Notice the SetIsOriginAllowed() and allowCreds() along with other policy settings, this works for me with POST calls to my api from my angular, which are running on two different port#s.

UPDATE:

Following the questions on the comments, adding additional information on how do we check the logged in user (windows auth) btwn api and the angular (frontend).

You can check the incoming User on a specific route that would only expect the authenticated user using the decoration [Authorize]. In my case, i would have only one method that would expect the windows user in the api:

[HttpGet("UserInfo")]
[Authorize]
public IActionResult GetUserInfo()
{
    string defaultCxtUser = HttpContext?.User?.Identity?.Name;

    if (defaultCxtUser != null && !string.IsNullOrEmpty(defaultCxtUser))
    {
        _logger.LogDebug($"START - Get Context user details for {defaultCxtUser}");
        ADHelper.logger = _logger;
        var userFullName = ADHelper.GetUserIdentityInfo(defaultCxtUser);
        _logger.LogInformation($"Context user {defaultCxtUser} with name: {userFullName}");
        var userInfo = new { Name = userFullName };
        //_logger.LogDebug($"END - GetUserInfo({defaultCxtUser} for {userFullName}");
        return Ok(userInfo);
    }
    else
        return Ok(new { Name = defaultCxtUser });
}

then i would call this from my angular with the service call as,

// Get the Logged in user info
GetCurrentUserInfo(): Observable<string> {
const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json'
  }),
  withCredentials: true
 };

// return this.http.get<string>(`${ApiPath}UserInfo`, httpOptions)
// .pipe(map(v => v as string));
return this.http.get<UserInfo>(`${ApiPath}UserInfo`, httpOptions)
.pipe(map(data => {
  // console.log(data, data.Name);
  return data.Name;
}))
;
}

Please see the headers with 'withCredentials: true' line that would trigger to pass the current user info, and it would be read and understood only if it has the authorize attr to read the User.Identity object in c# side. The reason we do this on a specific method is that, there should be some other parental method in the api like ApiStatus() or anything that could be, should be called first. This would ensure to also invoke the preflight check with OPTIONS that would require anonymous auth. Like in my case, getting whether the api is available and running, and some other app environment info before i get the userInfo() from my angular app.




回答2:


That's because your API is on different domain than your SPA angular application.

Please at this at the start of your Configure method in Startup.cs

if (env.IsDevelopment())
{
    app.UseCors(opts =>
    {
        opts.WithOrigins(new string[]
        {
            "http://localhost:3000",
            "http://localhost:3001"
            // whatever domain/port u are using
        });

        opts.AllowAnyHeader();
        opts.AllowAnyMethod();
        opts.AllowCredentials();
    });
}

Please note that this will handle only CORS for local development since you'll probably have same domain in production - if not, you'll need to reconfigure this for production also.

CORS blocking is browser specific and that's why it's working in PostMan but not in browser.



来源:https://stackoverflow.com/questions/60374968/response-to-preflight-request-doesnt-pass-access-control-check-it-does-not-hav

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!