Dostęp do usługi uwierzytelnionej ServiceStack za pomocą Ajax

Pracowałem za pomocą prostego przykładu API, zmodyfikowanej wersji przykładu ServiceStack Hello World z uwierzytelnianiem. Celem dowodu koncepcji jest stworzenie API RESTful, które zawiera usługi wymagające uwierzytelnienia dostępne wyłącznie poprzez Ajax z kilku różnych projektów internetowych.

Przeczytałem wiki i zaimplementowałem Uwierzytelnianie i autoryzację oraz implementację CORS (wiele, wyniki [przepraszam, za mało linków, aby wskazać odpowiedni link]). W tym momencie moja usługa Hello może uwierzytelnić się przy użyciu niestandardowego mechanizmu uwierzytelniania, który jest nadrzędny wobec CredentialsAuthProvider i niestandardowego obiektu sesji użytkownika. Stworzyłem lub pożyczyłem raczej prostą aplikację testową (całkowicie oddzielny projekt do symulacji naszych potrzeb) i możemy uwierzytelnić się, a następnie wywołać usługę Hello, przekazując nazwę i otrzymać odpowiedź „Hello Fred” za pośrednictwem jednego sesja przeglądarki. Oznacza to, że mogę wywołać ścieżkę / auth / credentials w adresie URL, przekazując nazwę użytkownika i id, i otrzymać prawidłową odpowiedź. Mogę wtedy zaktualizować adres URL do / hello / fred i otrzymać prawidłową odpowiedź.

Moje załamanie w zrozumieniu to jak zaimplementować uwierzytelnianie dla wszystkich wywołań ajax. Mój początkowy login działa poniżej. Bez względu na to, co robię, próba wywołania uwierzytelnionej usługi za pośrednictwem ajax, otrzymuję błąd OPTIONS 404 lub błąd Nie znaleziono lub Origin http // localhost: 12345 (pseudo-link) nie jest dozwolony przez Access-Control-Allow - Pochodzenie itp.

Czy muszę iśćta trasa?

Przepraszam, jeśli to jest mylące. W razie potrzeby mogę podać więcej szczegółów, ale uważam, że może to być wystarczające, aby pomóc kompetentnemu, aby pomóc mi w braku zrozumienia.

    function InvokeLogin() {
    var Basic = new Object();
    Basic.UserName = "MyUser";
   Basic.password = "MyPass";

    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        data: JSON.stringify(Basic),
        url: "http://localhost:58795/auth/credentials",
        success: function (data, textStatus, jqXHR) {
                alert('Authenticated! Now you can run Hello Service.');
            },
        error: function(xhr, textStatus, errorThrown) {
            var data = $.parseJSON(xhr.responseText);
            if (data === null)
                alert(textStatus + " HttpCode:" + xhr.status);
            else
                alert("ERROR: " + data.ResponseStatus.Message + (data.ResponseStatus.StackTrace ? " \r\n Stack:" + data.ResponseStatus.StackTrace : ""));
        }
    });
}

EDYTOWAĆ:

Na podstawie odpowiedzi i linku podanego przez Stefana dokonałem kilku zmian:

Moja konfiguracja (Uwaga: Używam niestandardowego uwierzytelniania i obiektu sesji i wszystko działa poprawnie).

public override void Configure(Funq.Container container)
{
    Plugins.Add(new AuthFeature(() => new CustomUserSession(), 
                new IAuthProvider[] {
                new CustomCredentialsAuthProvider(),
                    }));

    base.SetConfig(new EndpointHostConfig
    {
        GlobalResponseHeaders = {
            { "Access-Control-Allow-Origin", "*" },
            { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" },
            { "Access-Control-Allow-Headers", "Content-Type, Authorization" },
        },
        DefaultContentType = "application/json"
    });

    Plugins.Add(new CorsFeature());
    this.RequestFilters.Add((httpReq, httpRes, requestDto) =>
    {
        //Handles Request and closes Responses after emitting global HTTP Headers
        if (httpReq.HttpMethod == "OPTIONS")
            httpRes.EndRequest();   //   extension method
    });

    Routes
        .Add<Hello>("/Hello", "GET, OPTIONS");


    container.Register<ICacheClient>(new MemoryCacheClient());
    var userRep = new InMemoryAuthRepository();
    container.Register<IUserAuthRepository>(userRep);
}

My Simple Hello Service

[EnableCors]
public class HelloService : IService
{
    [Authenticate]
    public object GET(Hello request)
    {
        Looks strange when the name is null so we replace with a generic name.
        var name = request.Name ?? "John Doe";
        return new HelloResponse { Result = "Hello, " + name };
    }
}

Po wykonaniu wywołania logowania powyżej, moje kolejne wywołanie usługi Hello przynosi teraz błąd 401, który jest postępem, chociaż nie tam, gdzie powinienem być. (Jquery.support.cors = true jest ustawiony w moim pliku skryptu).

function helloService() {
    $.ajax({
        type: "GET",
        contentType: "application/json",
        dataType: "json",
        url: "http://localhost:58795/hello",
        success: function (data, textStatus, jqXHR) {
            alert(data.Result);
        },
        error: function (xhr, textStatus, errorThrown) {
            var data = $.parseJSON(xhr.responseText);
            if (data === null)
                alert(textStatus + " HttpCode:" + xhr.status);
            else
                alert("ERROR: " + data.ResponseStatus.Message +
                    (data.ResponseStatus.StackTrace ? " \r\n Stack:" + data.ResponseStatus.StackTrace : ""));
        }
    });
}

Ponownie, działa to w RESTConsole, jeśli najpierw poprawnie wykonam wywołanie / auth / credentials, a następnie wykonam wywołanie do / hello.

EDYCJA KOŃCOWA Podążając za radą Stefana, poniżej, w tym wiele innych linków, w końcu udało mi się to uruchomić. Oprócz kodu Stefana musiałem wykonać jedną dodatkową modyfikację:

Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization"));

Kolejne wyzwanie: aktualizacja kodu CustomAuthenticateAttibute Jonasa Erikssona (który wydaje się wykorzystywać starszą wersję ServiceStack, ponieważ kilka funkcji nie jest już dostępnych).

DZIĘKI PONOWNIE STEFAN !!

questionAnswers(1)

yourAnswerToTheQuestion