18 messaggi dal 07 gennaio 2016
Buongiorno, sto leggendo il libro su asp.net core 2.
Sto provando ad effettuare un autenticazione da un client WPF utilizzando il progetto di esempio ui-and-webapi-auth.
Vorrei capire meglio come richiamare il middleware creato per invocare il metodo invoke che si occupa della creazione del token JWT di autenticazione.

public async Task Invoke(HttpContext context) {
//Nel momento in cui un altro middleware produce la risposta
//emettiamo il token come intestazione
context.Response.OnStarting(() => {
var identity = context.User.Identity as ClaimsIdentity;
if (identity.IsAuthenticated && identity.AuthenticationType != CookieAuthenticationDefaults.AuthenticationScheme) {
//Invia un nuovo token come intestazione della risposta
//Il client potrà leggerlo e usarlo per la prossima richiesta
context.Response.Headers.Add("X-Token", tokenProvider.CreateToken(identity));
}
return Task.CompletedTask;
});
await next.Invoke(context);
}

Come riesco a utilizzare dal client questo middleware tramite una chiamata HTTP?

Devo recuperare dall'intestazione delle request il token? Avete un esempio anche semplice per capire come effettuare questa richiesta?

Grazie della risposta.

Marco.
Modificato da Pibe93 il 24 ottobre 2018 16.42 -
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao Marco,
grazie per aver acquistato il libro.

utilizzando il progetto di esempio ui-and-webapi-auth.

Ce l'ho presente, l'ho fatto io :) hai fatto bene a chiedere qui.


Vorrei capire meglio come richiamare il middleware

Non puoi richiamare un middleware perché è un componente della pipeline di ASP.NET Core, cioè lui osserva passare ogni singola richiesta HTTP e se lo reputa opportuno, può modificarla o modificare la risposta per il client.

Questo particolare middleware (che ho chiamato JwtTokenMiddleware) fa una cosa molto semplice: se la richiesta risulta autenticata, genera un nuovo token e lo infila in un'intestazione "X-Token" della risposta. Il suo comportamento è automatico, non è come l'action di un controller che va richiamata con una richiesta.

Quindi, quello che puoi fare per ottenere un token è autenticarti fornendo username e password. Per questo ho predisposto l'action Post nel TokenController che si trova in Controllers/Api. Quindi, dalla tua applicazione WPF fai una richiesta POST a /api/Token fornendo come corpo questo contenuto json:
{ "Username": "TuoUser", "Password": "TuaPassword" }

Questo utente ovviamente deve essere registrato.

Nella risposta che ti torna indietro troverai una intestazione "X-Token". Leggine il valore, perché lì troverai il token. Dalla seconda richiesta in poi, potrai usare questo token per l'autenticazione. Dovrai includerlo come intestazione Authorization della richiesta, in questo modo:
Authorization: Bearer TuoTokenQui


Dato che risulterai autenticato, il JwtTokenMiddleware ti emetterà un nuovo token che potrai usare nella tua successiva richiesta, e così il ciclo ricomincia.
Ogni token che ti viene emesso ha una scadenza molto breve, è per questo che te ne viene generato sempre uno nuovo. Se smetti di usare l'applicazione per un certo periodo di tempo (configurabile), allora sarai costretto a far reinserire all'utente username e password.


Avete un esempio anche semplice per capire come effettuare questa richiesta?

E' l'esempio ui-and-webapi-auth che te lo mostra, solo che è javascript e non WPF. Guarda la view /Views/Shared/_ApiDemo.cshtml. Dentro ci trovi il metodo getToken() che invia username e password a /api/Token per ottenere il token. Il token viene raccolto dalla risposta e salvato in una variabile javascript grazie al metodo ajaxSuccess, che va in esecuzione ogni volta che una richiesta ajax si completa.
A questo punto, dato che sei entrato in possesso di un token, puoi guardare la funzione javascript getUsers() che include il token nell'intestazione Authorization e invia la richiesta a /api/Users.

Fammi sapere se questo è sufficiente a chiarire o se ti occorrono altre informazioni.
Qui trovi un altro script sull'argomento e una discussione in fondo.
http://www.aspitalia.com/script/1288/Autenticazione-JWT-Token-ASP.NET-Core-Web-API.aspx

ciao,
Moreno

Enjoy learning and just keep making
18 messaggi dal 07 gennaio 2016
Ciao Moreno,
ti ringrazio per la risposta.
Allora avevo capito bene ma quando effettuo la richiesta dal mio client mi viene restituita una response con un codice di stato di errore.

Dove sbaglio? Credo che sbaglio ad utilizzare le classi HTTPClient e HTTPRequestMessage.

E' la prima volta che provo a utilizzarle, come le devo utilizzare?


Ad esempio ho effettuato la richiesta in questo modo solo per prova per vedere la response :

public async Task<string> LoginAsync(string userName, string password)

{

//var keyValues = new List<KeyValuePair<string, string>>

//{

// new KeyValuePair<string, string>("username", userName),

// new KeyValuePair<string, string>("password", password),

// new KeyValuePair<string, string>("grant_type", "password")

//};




var client = new HttpClient();

client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:61308/" + "api/Token");

//request.Content = new FormUrlEncodedContent(keyValues);


request.Content = new StringContent("{\"username\":\"prova@gmail.com\",\"password\":Pippo-100}",
Encoding.UTF8,
"application/json");

var response = await client.SendAsync(request);



var content = await response.Content.ReadAsStringAsync();




var accessToken = "";

return accessToken;

}

le parti remmate le avevo utilizzate prima ma ho cambiato provando in un altro modo ma nella variabile content mi restituisce Code Status : 400 Bad Request.

Grazie in anticipo per la risposta.

Marco.
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao Marco,

Credo che il problema fosse che non avevi messo le virgolette attorno alla password Pippo-100. In pratica, non stavi inviando contenuto json valido e penso sia questo il motivo per cui la api ti risponde con 400 Bad Request.

Comunque, non devi comporre il json a mano ma puoi sfruttare il pacchetto NuGet Newtonsoft.Json, che devi installare nel tuo progetto.

A questo punto riscrivi il metodo LoginAsync in questo modo:
private async Task<string> LoginAsync(string username, string password)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri("http://localhost:5000/api/");
        var payload = new
        {
            Username = username,
            Password = password
        };
        var jsonContent = JsonConvert.SerializeObject(payload);
        var requestContent = new StringContent(jsonContent, Encoding.UTF8, "application/json");
        var response = await client.PostAsync("Token", requestContent);

        //Prima di leggere il token verifichiamo che la risposta abbia uno status code di successo (es. 200)
        if (!response.IsSuccessStatusCode)
        {
            return null;
        }

        const string tokenHeaderName = "X-Token";
        //Verifichiammo anche se nella risposta c'è l'intestazione X-Token
        if (!response.Headers.Contains(tokenHeaderName))
        {
            return null;
        }
        //Ok, abbiamo passato tutti i controlli, quindi restituiamo il token al chiamante
        return response.Headers.GetValues(tokenHeaderName).First();
    }
}

Come vedi ho creato un oggetto anonimo contenente le proprietà Username e Password e poi l'ho dato in pasto al metodo JsonConvert.SerializeObject. L'oggetto può anche non essere anonimo ma ti puoi proprio creare una classe come la TokenRequest dell'esempio, che conterrà le stesse proprietà Username e password. E quindi faresti:
var payload = new TokenRequest
        {
            Username = username,
            Password = password
        };


L'url base della API (cioè http://localhost:5000/api/ nel mio caso) potresti metterlo nel file .config dell'applicazione WPF, in modo che se cambia non sarai costretto a ricompilare l'applicazione.

Nelle successive richieste con HttpClient, quando dovrai includere il token tra le intestazioni, usa questo codice. Qui token è una variabile stringa che contiene il valore restituito da LoginAsync.
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");


ciao,
Moreno

Enjoy learning and just keep making
18 messaggi dal 07 gennaio 2016
Ciao Moreno,
ho provato al volo e cosi funziona.
Avevo compilato a mano per fare una prova ma a quanto pare avevo sbagliato.
In ogni caso cosi è tutto molto chiaro sei un grande!!
Ti ringrazio appena torno da lavoro farò delle prove in più per capire meglio il tutto, nel caso ti disturberò ancora qui sul forum con altre domande.

Ti ringrazio davvero molto sei sempre chiaro come pochi!!

Grazie mille Moreno.

Ciao,

Marco.
11.886 messaggi dal 09 febbraio 2002
Contributi
Ottimo, grazie Marco!
Sì, se hai altre domande scrivi pure.

Enjoy learning and just keep making
18 messaggi dal 07 gennaio 2016
Ciao Moreno,
volevo chiederti un altra cosa se possibile.
In un progetto che ho creato ho aggiunto la webapi come nel tue esempio per l'autenticazione e se ora voglio aggiungere un altro progetto ad esempio che contiene il model dei dati con entity framework core su cui tramite richieste HTTP ad esempio mi leggo / scrivo i dati magari dei clienti e cosi via, lo aggiungo come class library?

Grazie in anticipo della risposta.

Marco.
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao Marco,

lo aggiungo come class library?

Come preferisci tu. Lo puoi tenere nel progetto ASP.NET Core oppure in una class library separata.

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.