CORS: tryb poświadczeń to „dołącz”

103

Tak, wiem, o czym myślisz - kolejne pytanie CORS-a, ale tym razem jestem zaskoczony.

Na początek rzeczywisty komunikat o błędzie:

XMLHttpRequest nie może załadować http: //localhost/Foo.API/token . Wartość nagłówka „Access-Control-Allow-Origin” w odpowiedzi nie może być symbolem wieloznacznym „*”, gdy tryb poświadczeń żądania to „include” . Dlatego źródło „ http: // localhost: 5000 ” nie ma dostępu. Tryb poświadczeń żądań inicjowanych przez XMLHttpRequest jest kontrolowany przez atrybut withCredentials.

Nie jestem pewien, co oznacza tryb poświadczeń „dołączanie” ?

Kiedy więc wykonuję żądanie w listonoszu, nie ma takiego błędu:

wprowadź opis obrazu tutaj

Ale kiedy uzyskuję dostęp do tego samego żądania za pośrednictwem mojej aplikacji internetowej angularjs, jestem zaskoczony tym błędem. Oto moje żądanie / odpowiedź angualrjs. Jak zobaczysz, odpowiedź brzmi OK 200, ale nadal otrzymuję błąd CORS:

Prośba i odpowiedź Fiddlera:

Poniższy obraz przedstawia żądanie i odpowiedź z frontonu internetowego do interfejsu API

Skrzypek

Na podstawie wszystkich innych postów, które przeczytałem w Internecie, wydaje się , że postępuję właściwie, dlatego nie mogę zrozumieć błędu. Na koniec, oto kod, którego używam w angualrjs (fabryka logowania):

wprowadź opis obrazu tutaj

Implementacja CORS w API - cele referencyjne:

Zastosowana metoda 1:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        EnableCrossSiteRequests(config);
    }

    private static void EnableCrossSiteRequests(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute("*", "*", "*")
        {
            SupportsCredentials = true
        };
        config.EnableCors(cors);
    }
}

Zastosowana metoda 2:

public void Configuration(IAppBuilder app)
{
    HttpConfiguration config = new HttpConfiguration();

    ConfigureOAuth(app);

    WebApiConfig.Register(config);
    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    app.UseWebApi(config);

}

Z góry bardzo dziękuję!

Richard Bailey
źródło
ładne zdjęcia, czego one dotyczą? Aby odpowiedzieć na twoje pytanie, jeśli włączysz uwierzytelnianie, odpowiedź kontroli dostępu musi być hostem źródłowym (strona przeglądarki), nie może być *- więc strona serwera robi źle CORS - och, a listonosz działa, ponieważ to nie jest prośba o krzyżowe pochodzenie
Jaromanda X
@JaromandaX, dzięki za odpowiedź. Zdjęcia przedstawiają żądanie / odpowiedź, a także pokazują przekazywane nagłówki. Zadajesz pytanie, oczywiście stwierdzasz, że nie osiągnął swojego celu ...
Richard Bailey
Mój komentarz powinien być wszystkim, co musisz wiedzieć - nie trzeba było oglądać zdjęć
Jaromanda X
Niedawno zdecydowałem się odejść od plików cookie w moim internetowym interfejsie API i raczej korzystać z tokenów. Kiedy użyłem plików cookie, mój CORS działa bez żadnych problemów. Dlatego staram się zrozumieć, dlaczego CORS nie jest poprawnie zaimplementowany po stronie serwera
Richard Bailey
1
jeśli włączysz uwierzytelnianie, access-control-allow-originodpowiedź musi być hostem źródłowym (strona przeglądarki), nie może być*
Jaromanda X

Odpowiedzi:

105

Problem wynika z twojego kodu Angular:

Gdy withCredentialsjest ustawiona na true, próbuje wysłać poświadczenia lub pliki cookie wraz z żądaniem. Ponieważ oznacza to, że inne źródło potencjalnie próbuje wykonać uwierzytelnione żądania, symbol wieloznaczny („*”) nie jest dozwolony jako nagłówek „Access-Control-Allow-Origin”.

Aby to zadziałało, musiałbyś wyraźnie odpowiedzieć, podając źródło, które wysłało żądanie, w nagłówku „Access-Control-Allow-Origin”.

Zalecałbym jawne umieszczenie na białej liście źródeł, które chcesz zezwolić na wysyłanie uwierzytelnionych żądań, ponieważ po prostu odpowiadanie na źródło z żądania oznacza, że ​​każda dana witryna może wykonywać uwierzytelnione połączenia do twojego zaplecza, jeśli użytkownik ma ważną sesję.

Wyjaśniam to w tym artykule, który napisałem jakiś czas temu.

Możesz więc ustawić withCredentialsna fałsz lub zaimplementować białą listę pochodzenia i odpowiadać na żądania CORS z prawidłowym źródłem, ilekroć dotyczy to poświadczeń

geekonaut
źródło
4
Pracuję nad aplikacją Angular 5 z TypeScript. Muszę podać withCredentials jako prawdziwe, w przeciwnym razie otrzymam wyjątek Authorization Failed. Jak rozwiązać ten problem za pomocą poświadczeń: prawda
Ziggler
@Ziggler Miałem taką samą sytuację. Czy znajdujesz rozwiązania?
Pavel
@Ziggler Zapłaciłem za rozwiązanie, zobacz moją odpowiedź.
Pavel
1
Nadal pojawia się ten błąd, gdy używam WithCredentials = TRUE i Access-Control-Allow-Origin = [' localhost: 4200'] i NIE używam gwiazdki *, więc komunikat o błędzie nie ma już sensu. KOMUNIKAT O BŁĘDZIE: „Odpowiedź na żądanie inspekcji wstępnej nie przechodzi kontroli dostępu: Wartość nagłówka„ Access-Control-Allow-Origin ”w odpowiedzi nie może być symbolem wieloznacznym *, gdy tryb poświadczeń żądania to„ dołącz ”. Pochodzenie. Dlatego „ localhost: 4200 ” nie ma pozwolenia na dostęp. Tryb poświadczeń żądań zainicjowanych przez XMLHttpRequest jest kontrolowany przez atrybut withCredentials. "
mruanova
@mruanova Czy na pewno nagłówek Access-Control-Allow-Origin jest poprawnie ustawiony w żądaniu? Wygląda na to, że coś zostało gdzieś wysłane z dziką kartą
geekonauta,
15

Jeśli używasz oprogramowania pośredniczącego CORS i chcesz wysłać wartość withCredentialslogiczną true, możesz skonfigurować CORS w następujący sposób:

var cors = require('cors');    
app.use(cors({credentials: true, origin: 'http://localhost:5000'}));

`

Ankur Kedia
źródło
11

Dostosowywanie CORS dla Angular 5 i Spring Security (rozwiązanie bazowe plików cookie)

Po stronie Angular wymagane jest dodanie flagi opcji withCredentials: truedla transportu Cookie:

constructor(public http: HttpClient) {
}

public get(url: string = ''): Observable<any> {
    return this.http.get(url, { withCredentials: true });
}

Po stronie serwera Java wymagane dodanie CorsConfigurationSourcedo konfiguracji zasad CORS:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        // This Origin header you can see that in Network tab
        configuration.setAllowedOrigins(Arrays.asList("http:/url_1", "http:/url_2")); 
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        configuration.setAllowedHeaders(Arrays.asList("content-type"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()...
    }
}

Metoda configure(HttpSecurity http)domyślnie będzie używana corsConfigurationSourcedlahttp.cors()

Pavel
źródło
1

Jeśli to pomogło, użyłem wirówki z moją aplikacją reagjs i po sprawdzeniu kilku poniższych komentarzy spojrzałem na plik biblioteki centrifuge.js, która w mojej wersji zawierała następujący fragment kodu:

if ('withCredentials' in xhr) {
 xhr.withCredentials = true;
}

Po usunięciu tych trzech linii aplikacja działała dobrze, zgodnie z oczekiwaniami.

Mam nadzieję, że to pomoże!

Gustavo Garcia
źródło
1

Jeśli używasz .NET Core, będziesz musiał .AllowCredentials () podczas konfigurowania CORS w Startup.CS.

Wewnątrz ConfigureServices

services.AddCors(o => {
    o.AddPolicy("AllowSetOrigins", options =>
    {
        options.WithOrigins("https://localhost:xxxx");
        options.AllowAnyHeader();
        options.AllowAnyMethod();
        options.AllowCredentials();
    });
});

services.AddMvc();

Następnie wewnątrz Configure:

app.UseCors("AllowSetOrigins");
app.UseMvc(routes =>
    {
        // Routing code here
    });

U mnie brakowało po prostu opcji AllowCredentials (), które spowodowały wspomniany błąd. Na marginesie, w przypadku innych osób mających również problemy z CORS, kolejność ma znaczenie, a AddCors () musi zostać zarejestrowana przed AddMVC () wewnątrz klasy Startup.

Steven Pfeifer
źródło
0

Po prostu dodaj Axios.defaults.withCredentials=truezamiast ( {credentials: true}) po stronie klienta i zmień app.use(cors())na

app.use(cors(
  {origin: ['your client side server'],
  methods: ['GET', 'POST'],
  credentials:true,
}
))
Dev Essence
źródło