Se si desidera identificare il client e autorizzarlo, è possibile sovrascrivere il metodo ValidateClientAuthentication
.
Nell'esempio di Taiseer aver collegato troverete un codice:
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
e una nota che dice:
Come si nota questa classe eredita dalla classe “OAuthAuthorizationServerProvider”, noi' hai ridefinito due metodi "ValidateClientAuthentication" e "GrantResourceOwnerCredentials". Il primo metodo è responsabile per la convalida del "Client", nel nostro caso abbiamo un solo client, quindi restituiremo sempre il suo validato con successo.
Se si desidera convalidare il client, è necessario inserire un po 'di logica.
Normalmente si passa un clientId
e un clientSecret
nell'intestazione della propria richiesta http, in modo da poter convalidare la richiesta del client con alcuni parametri del database, ad esempio.
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId = string.Empty;
string clientSecret = string.Empty;
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
{
context.TryGetFormCredentials(out clientId, out clientSecret);
}
if (context.ClientId == null)
{
context.SetError("invalid_client", "Client credentials could not be retrieved through the Authorization header.");
context.Rejected();
return;
}
try
{
// You're going to check the client's credentials on a database.
if (clientId == "MyApp" && clientSecret == "MySecret")
{
context.Validated(clientId);
}
else
{
// Client could not be validated.
context.SetError("invalid_client", "Client credentials are invalid.");
context.Rejected();
}
}
catch (Exception ex)
{
string errorMessage = ex.Message;
context.SetError("server_error");
context.Rejected();
}
return;
}
Nell'esempio di cui sopra si cercherà di estrarre le credenziali client inviati nell'intestazione della richiesta:
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
{
context.TryGetFormCredentials(out clientId, out clientSecret);
}
e convalidato:
// You're going to check the client's credentials on a database.
if (clientId == "MyApp" && clientSecret == "MySecret")
{
context.Validated(clientId);
}
se il client invia un'intestazione di richiesta errata è necessario rifiutare la richiesta:
context.SetError("invalid_client", "Client credentials are invalid.");
context.Rejected();
Il metodo ValidateClientAuthentication
viene elaborato prima di GrantResourceOwnerCredentials
. In questo modo è possibile estenderlo e passare a GrantResourceOwnerCredentials alcune informazioni aggiuntive necessarie.
In una delle mie applicazioni ho creato una classe:
class ApplicationClient
{
public string Id { get; set; }
public string Name { get; set; }
public string ClientSecretHash { get; set; }
public OAuthGrant AllowedGrant { get; set; }
public DateTimeOffset CreatedOn { get; set; }
}
che uso in ValidateClientAuthentication subito dopo ho controllato il clientId e il segreto sono ok:
if (clientId == "MyApp" && clientSecret == "MySecret")
{
ApplicationClient client = new ApplicationClient();
client.Id = clientId;
client.AllowedGrant = OAuthGrant.ResourceOwner;
client.ClientSecretHash = new PasswordHasher().HashPassword("MySecret");
client.Name = "My App";
client.CreatedOn = DateTimeOffset.UtcNow;
context.OwinContext.Set<ApplicationClient>("oauth:client", client);
context.Validated(clientId);
}
Come potete vedere qui
context.OwinContext.Set<ApplicationClient>("oauth:client", client);
Sto impostando una variabile Owin che posso leggere in seguito. Nella tua GrantResourceOwnerCredentials
ora si può leggere la variabile in caso di necessità:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
ApplicationClient client = context.OwinContext.Get<ApplicationClient>("oauth:client");
...
}
Ora, se si vuole recuperare il token portatore - che si sta andando da utilizzare per tutte le chiamate API sicure - è necessario codificare il clientId
e clientSecret
(base64) e passarlo nell'intestazione della richiesta:
una richiesta Ajax con jQuery sarebbe simile a questa:
var clientId = "MyApp";
var clientSecret = "MySecret";
var authorizationBasic = $.base64.btoa(clientId + ':' + clientSecret);
$.ajax({
type: 'POST',
url: '<your API token validator>',
data: { username: 'John', password: 'Smith', grant_type: 'password' },
dataType: "json",
contentType: 'application/x-www-form-urlencoded; charset=utf-8',
xhrFields: {
withCredentials: true
},
headers: {
'Authorization': 'Basic ' + authorizationBasic
},
beforeSend: function (xhr) {
},
success: function (result) {
var token = result.access_token;
},
error: function (req, status, error) {
alert(error);
}
});
come potete vedere ho anche aggiunto il nome utente e password - con il g rant tipo - nel corpo della richiesta:
data: { username: 'John', password: 'Smith', grant_type: 'password' }
modo che il server sarà in grado di convalidare il cliente (clientId + clientSecret) e l'utente (username + password).
Se la richiesta è successo si dovrebbe tornare un gettone valida:
oAuth.Token = result.access_token;
che è possibile memorizzare da qualche parte per le seguenti richieste.
Ora è possibile utilizzare questo token per tutte le richieste al api:
$.ajax({
type: 'GET',
url: 'myapi/fetchCustomer/001',
data: { },
dataType: "json",
headers: {
'Authorization': 'Bearer ' + oAuth.Token
},
success: function (result) {
// your customer is in the result.
},
error: function (req, status, error) {
alert(error);
}
});
Un'altra cosa che si potrebbe desiderare di aggiungere alla vostra API durante l'avvio è SuppressDefaultHostAuthentication
:
config.SuppressDefaultHostAuthentication();
questo è un metodo di estensione di HttpConfiguration
. Poiché utilizzi token bearer, vuoi sopprimere il meccanismo di autenticazione standard basato su cookie.
Taiseer ha scritto un'altra serie di articles che vale la pena leggere dove spiega tutte queste cose.
Ho creato un github repo in cui è possibile vedere come funziona.
L'API Web è auto-ospitata e ci sono due client: jQuery e Applicazione Console.
Che risposta perfetta e ben strutturata! Metterò alla prova la tua soluzione. Grazie. –
Fammi sapere come va. Ho passato un po 'di tempo a cercare di capire come tutti questi pezzi combaciano. Non è stato facile, soprattutto perché non c'è molta documentazione online. – LeftyX
Sì, hai ragione, ho passato due giorni solo per l'apprendimento della struttura a causa della mancanza di documentazione. Segnalerò il risultato :) –