Połączyć wykorzystanie uwierzytelniania zarówno dla stron MVC, jak i stron Web API?

Mam aplikację internetową MVC 5 i mogę się zalogować za pomocą loginu.strona cshtml i pobierz plik cookie, a logowanie działa dobrze. Ale, chciałbym zrobić logowanie za pomocą Web API, a następnie (być może) ustawić plik cookie tak, że jestem zalogowany do moich stron MVC... (lub zaloguj się za pomocą loginu MVC, a następnie uzyskaj dostęp do Web API) jednak web api zwraca token okaziciela, a nie token cookie... więc to nie działa. Czy istnieje sposób na połączenie uwierzytelniania zarówno dla moich stron MVC, jak i dla mojego Web API strony?

UPDATE:

To nie jest problem z kodem, raczej problem koncepcyjny.

Zwykłe strony MVC sprawdzają plik cookie o nazwie, domyślnie,".AspNet.ApplicationCookie " w celu ustalenia tożsamości żądających. Ten plik cookie jest generowany przez wywołanie Applicationsignmanager.Passwordsignasync.

Wywołania WebAPI sprawdzają natomiast nagłówki żądań w poszukiwaniu elementu o nazwie Authorization... i używa tej wartości do określenia tożsamości żądających. To jest zwracane z wywołania WebAPI do "/ Token".

Są to bardzo różne wartości. Moja strona musi używać zarówno MVC pages jak i WebAPI (aby dynamicznie aktualizować te strony)... i oba muszą być uwierzytelnione, aby wykonywać swoje zadania.

Jedyną metodą, jaką przychodzi mi do głowy, jest dwukrotne uwierzytelnienie... raz z wywołaniem WebAPI i ponownie z postem logowania. (patrz moja odpowiedź poniżej).

To wydaje się bardzo trudne... ale nie rozumiem kodu autoryzacyjnego na tyle, by wiedzieć, czy istnieje bardziej właściwy sposób osiągnięcia tego.

Author: Brian Rice, 2015-08-23

6 answers

Najlepszym sposobem, aby to osiągnąć, jest posiadanie serwera autoryzacji (Web API generującego token) i średniego zużycia tokenów w projekcie MVC. IdentityServer powinien pomóc. Jednak zrobiłem to tak:

Zbudowałem serwer autoryzacji używając JWT z Web API i ASP.Net tożsamość jak wyjaśniono tutaj .

Gdy to zrobisz, Twoje API internetowe startup.cs będą wyglądać tak:
 // Configures cookie auth for web apps and JWT for SPA,Mobile apps
 private void ConfigureOAuthTokenGeneration(IAppBuilder app)
 {
    // Configure the db context, user manager and role manager to use a single instance per request
    app.CreatePerOwinContext(ApplicationDbContext.Create);
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
    app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);

    // Cookie for old school MVC application
    var cookieOptions = new CookieAuthenticationOptions
    {
        AuthenticationMode = AuthenticationMode.Active,
        CookieHttpOnly = true, // JavaScript should use the Bearer
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,                
        LoginPath = new PathString("/api/Account/Login"),
        CookieName = "AuthCookie"
    };
    // Plugin the OAuth bearer JSON Web Token tokens generation and Consumption will be here
    app.UseCookieAuthentication(cookieOptions);

    OAuthServerOptions = new OAuthAuthorizationServerOptions()
    {
        //For Dev enviroment only (on production should be AllowInsecureHttp = false)
        AllowInsecureHttp = true,
        TokenEndpointPath = new PathString("/oauth/token"),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(30),
        Provider = new CustomOAuthProvider(),                
        AccessTokenFormat = new CustomJwtFormat(ConfigurationManager.AppSettings["JWTPath"])
    };

    // OAuth 2.0 Bearer Access Token Generation
    app.UseOAuthAuthorizationServer(OAuthServerOptions);
}

Można znaleźć Klasy CustomOAuthProvider i CustomJwtFormat tutaj .

Napisałem logikę konsumpcji (tj. middleware) we wszystkich moich innych API (serwerach zasobów), które chciałem zabezpieczyć za pomocą tego samego tokena. Ponieważ chcesz wykorzystać token wygenerowany przez Web API w projekcie MVC, po zaimplementowaniu serwera autoryzacji musisz:

W aplikacji MVC dodaj to w startup.cs:

public void Configuration(IAppBuilder app)
{
        ConfigureOAuthTokenConsumption(app);
}

private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
    var issuer = ConfigurationManager.AppSettings["AuthIssuer"];
    string audienceid = ConfigurationManager.AppSettings["AudienceId"];
    byte[] audiencesecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["AudienceSecret"]);

    app.UseCookieAuthentication(new CookieAuthenticationOptions { CookieName = "AuthCookie" , AuthenticationType=DefaultAuthenticationTypes.ApplicationCookie });

    //// Api controllers with an [Authorize] attribute will be validated with JWT
    app.UseJwtBearerAuthentication(
        new JwtBearerAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Passive,
            AuthenticationType = "JWT",
            AllowedAudiences = new[] { audienceid },
            IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
            {
                new SymmetricKeyIssuerSecurityTokenProvider(issuer, audiencesecret)                           
            }

        });
}

W kontrolerze MVC, gdy otrzymasz token, usuń go serializuj i wygeneruj plik cookie z dostępu token:

AccessClaims claimsToken = new AccessClaims();
claimsToken = JsonConvert.DeserializeObject<AccessClaims>(response.Content);
claimsToken.Cookie = response.Cookies[0].Value;               
Request.Headers.Add("Authorization", "bearer " + claimsToken.access_token);
var ctx = Request.GetOwinContext();
var authenticateResult = await ctx.Authentication.AuthenticateAsync("JWT");
ctx.Authentication.SignOut("JWT");
var applicationCookieIdentity = new ClaimsIdentity(authenticateResult.Identity.Claims, DefaultAuthenticationTypes.ApplicationCookie);
ctx.Authentication.SignIn(applicationCookieIdentity);

Wygeneruj klucz maszynowy i dodaj go do web.config swojego API internetowego i ASP.Net miejsce w MVC.

W ten sposób zostanie utworzony plik cookie, a atrybut [Authorize] w witrynie MVC i Web API będzie honorował ten plik cookie.

P. S. zrobiłem to z Web API wydającym JWT (serwer autoryzacji lub serwer Auth & resource) i byłem w stanie go wykorzystać w ASP.Net MVC website, SPA Site built in Angular, secure API built in python (resource server), spring (resource server) oraz aplikację na Androida.

 8
Author: Ravi A.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-16 10:07:34

Ugg... musiałem użyć loginu.formularz cshtml i nadpisanie zgłoszenia... wykonaj połączenie Ajax, aby uzyskać token na okaziciela WebApi... a następnie prześlij formularz, aby uzyskać rzeczywisty plik cookie MVC. Więc składam dwie prośby o zalogowanie... jeden dla tokena WebApi, a drugi dla pliku cookie MVC.

Wydaje mi się to dość trudne... byłoby miło, gdyby był jakiś sposób, aby zalogować się do MVC za pomocą tokena na okaziciela... lub połączenie do WebApi, które zwróci mi plik cookie, którego mogę użyć do zwykłe żądania stron MVC. Jeśli ktoś ma lepszy sposób, chętnie go usłyszę.

To jest kod skryptu, który dodałem do logowania.cshtml:

    $(document).ready(function () {
        $('form:first').submit(function (e) {
            e.preventDefault();
            var $form = $(this);
            var formData = $form.serializeObject(); // https://github.com/macek/jquery-serialize-object
            formData.grant_type = "password";
            $.ajax({
                type: "POST",
                url: '@Url.Content("~/Token")',
                dataType: "json",
                data: formData, // seems like the data must be in json format
                success: function (data) {
                    sessionStorage.setItem('token', data.access_token);
                    $form.get(0).submit(); // do the actual page post now
                },
                error: function (textStatus, errorThrown) {
                }
            });
        });
    });
 2
Author: Brian Rice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-23 15:50:19

Zakładam, że próbujesz zrobić to, aby strony obsługiwane przez MVC miały javascript, który wywołuje metody Web API. Jeśli używasz ASP.NET tożsamość do obsługi uwierzytelniania (co wygląda na to, że robisz), MVC powinien używać tokenów OAuth, które mogą być przekazywane do Web API w celu uwierzytelnienia.

Oto fragment kodu javascript, który działa u mnie w podobnej sytuacji:

var token = sessionStorage.getItem('access_token');
var headers = {};
if (token) {
    headers.Authorization = 'Bearer ' + token;
}
$.ajax({
    type: <GET/POSt/...>,
    url: <your api>,
    headers: headers
}).done(function (result, textStatus) {
 1
Author: DavidS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-24 16:27:43

Mam podobny przypadek z tobą, ale używam innego sposobu uwierzytelniania.

Mam web i api, które wszystko dla użytkowników intranetu. Nie używam tożsamości użytkownika, aby przejść przez internet i api. Zamiast tego utworzyłem indywidualne konto internetowe i za każdym razem web będzie używać tego specjalnego konta do łączenia się z api.

Ponieważ musimy również upewnić się, że użytkownicy nie powinni łączyć się bezpośrednio z api. Powinny one łączyć się tylko z web ui.

Mam nadzieję, że to ci pomoże.

 0
Author: Xin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-23 00:47:03

Oto rozwiązanie twojego problemu. Możesz użyć Auth0 tutaj link

  1. Użytkownik wprowadza swoje dane logowania Serwer weryfikuje poprawność poświadczeń i zwraca podpisany token

  2. Token ten jest przechowywany po stronie klienta, najczęściej w pamięci lokalnej - ale może być przechowywany w pamięci sesji lub pliku cookie, jak również

  3. Kolejne żądania do serwera zawierają ten token jako dodatkowy nagłówek autoryzacji lub za pośrednictwem jednego z innych metody wymienione powyżej

  4. Serwer dekoduje JWT i jeśli token jest poprawny przetwarza request

  5. Po wylogowaniu się użytkownika token jest niszczony po stronie klienta, nie konieczna jest interakcja z serwerem

 0
Author: Pritish Vaidya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-30 15:51:03

Z twoich komentarzy powyżej, z tego co rozumiem, masz scenariusz, w którym wykonujesz logowanie przez przeglądarkę, ale także musisz wywoływać metody web-api za pomocą wywołań ajax.

Wywołania przeglądarki są oparte na plikach cookie sesji. Podczas gdy połączenia ajax z przeglądarki miałyby plik cookie sesji w nagłówku, co jest wymagane jest nagłówek uwierzytelniania być obecny dla web-api do przeprowadzenia walidacji.

Więc przy pomyślnym logowaniu trzeba by również wygenerować web-api oparte token, ustaw go jako plik cookie (który jest dostępny przez javascript), a następnie podczas wykonywania połączeń ajax, podnieś go z pliku cookie i dołącz go jako nagłówek w nagłówku' Authorization'.

 0
Author: Ravindra HV,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-30 21:04:58