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ę!


ł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ń


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'}));

`


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()


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!


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.


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,
}
))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.