Problem z CORS, Działa połowicznie.

0

Mam WebApi, gdzie stosuję CORS. Gdy wywołuję zapytania do kontrolerów wszystko ładnie działa. Jednak, kiedy wysyłam zapytanie, aby wygenerować token dostaję kod 400 .

 Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:54520' is therefore not allowed access. The response had HTTP status code 400.

Kod Startup

 public static void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();
            
            ConfigureOAuth(app);
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            WebApiConfig.Register(config);
            
            app.UseWebApi(config);
        }

        private static void ConfigureOAuth(IAppBuilder app)
        {

            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
           {
               AllowInsecureHttp = true,
               TokenEndpointPath = new PathString("/api/token"),
               AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
               Provider = new AuthorizationServerProvider()
           };

            app.UseOAuthAuthorizationServer(OAuthServerOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }

kod AuthorizationServerProvider

public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
        }

 public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {

        
            using (AuthRepository repo = new AuthRepository())
            {
                IdentityUser user = await repo.FindUser(context.UserName, context.Password);

                if (user == null)
                {
                    context.SetError("invalid_grant", "The user name or password is incorrect.");
                    return;
                }
                var identity = new ClaimsIdentity(context.Options.AuthenticationType);
                identity.AddClaim(new Claim("sub", context.UserName));
                identity.AddClaim(new Claim("role", "user"));

                context.Validated(identity);
            }
        }

W żadnym innym miejscu projektu nie mam innej konfiguracji CORS.

0

Pokaż przyjacielu jak wysyłasz żądanie przez http.

0

Ewentualnie dorzuciłbym jeszcze odblokowanie CORSa w pliku w któym rejestruje się routing dla API:

config.Routes.MapHttpRoute(...);
EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*"):
config.EnableCors(cors);

I tak na dobrą sprawę to powinno wystarczyć. O "gwiazdkach" poczytaj w internecie, generalnie chodzi o zawężenie typów żądań, adresów z których można to robić itp.

0
 var data = "grant_type=password&username=" + userName + "&password=" + password;
            $.ajax({
                url: 'http://localhost:60967/api/token',
                type: 'POST',
                dataType: "json",
                contentType: 'application/json; charset=utf-8',
                data: data,
                async: true,
                processData: false,
                cache: false,
                withCredentials: true,
                success: function (ret)
                {
                    console.log(ret);
                },
                error: function(ret)
                {
                    console.log(ret);
                }
            });

Tak samo wysyłam zapytania do kontrolerów webapi i działa.

0

W AuthorizationServerProvider dodałem

public override Task MatchEndpoint(OAuthMatchEndpointContext context)
        {
            context.Response.Headers.Add("Access-Control-Allow-Origin",
                                                     new string[] { "*" });
            context.Response.Headers.Add("Access-Control-Allow-Headers",
                                   new string[] { "*" });
            context.Response.Headers.Add("Access-Control-Allow-Methods",
                                   new string[] { "*" });

            if (context.Request.Method == "OPTIONS")
            {
                context.RequestCompleted();
                return Task.FromResult(0);
            }

            return base.MatchEndpoint(context);
        }

 

dostaję

Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response. 

Zmiany contentType na te podane w dokumentacji jquery powodują błąd 500

0

Tak się składa, że w tym momencie walczę dokładnie z tym samym problemem.
U mnie CORS działa, tak wygląda mój plik WebApiConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using Microsoft.Owin.Security.OAuth;
using Newtonsoft.Json.Serialization;
using System.Web.Http.Cors;

namespace WebApiScheme
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            // Configure Web API to use only bearer token authentication.
            config.SuppressDefaultHostAuthentication();
            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
            config.EnableCors(cors);
        }
    }
}

Tak wygląda moje zapytanie w jQuery.

  $.ajax({
      
                    url: 'http://localhost:50852/token',
                    crossDomain: true,   
                    crossOrigin:true,
                    method: 'POST',
                    contentType: 'application/json',
                    data: {
                        grant_type: 'password',
                        username: $('#txtUsername').val(),
                        password: $('#txtPassword').val()
                    },
                    success: function (response) {
                        sessionStorage.setItem('accessToken', response.access_token);
                    },
                    error: function (jqHXR) {
                        $('#divErrorText').text(jqHXR.responseText);
                        $('#divError').show('fade');
                    }
                });

Co ciekawe powyższa metoda działa przy użyciu IE i Fiddlera, tj. dostaję token w odpowiedzi, których schodzi z kontrolera dziedziczącego po ApiController.
Niestety powyższa metoda nie działa w Chromie, co mnie bardzo boli. Dostaję komunikat z informacją "unsupported_grant_type".

Pomoże ktoś w tym temacie?

0

Dla osobników, którzy mają podobny problem. Wystarczy wszystko ładnie sprawdzić debugerem, zrobić sobie zapytanie Fiddlerem i sprawdzić kod błędu. Przy okazji zrobić lepszą obsługę błędów. Dzieki temu dowiedziałem się, że zamiast

 EFDbContext : IdentityDbContext<IdentityUser>

zrobiłem

 EFDbContext : IdentityDbContext<User>

gdzie User to model dziedziczący po IdentityUser.

Code-First połączenie do bazy danych.

1 użytkowników online, w tym zalogowanych: 0, gości: 1