web-dev-qa-db-fra.com

Méthode de connexion à l'API Web ASP.NET

Je souhaite créer un service Web RESTful à l'aide de l'API Web ASP.NET que des développeurs tiers utiliseront pour accéder aux données de mon application. 

Dans Visual Studio, j'ai décidé de créer un nouveau projet ASP.NET. J'ai suivi ce tutorial mais j'ai choisi un autre modèle: le modèle API Web. J'utilise une base de données MySQL avec les tables de rôles d'utilisateur standard, comme expliqué dans le tutoriel.

Le modèle contient de nombreuses méthodes très intéressantes pour enregistrer un nouvel utilisateur, mais il n'y a pas de demande de connexion par défaut. J'ai écrit ceci sans comprendre ce que je fais:

    // POST api/Account/Login
    [Route("Login")]
    public IHttpActionResult Login(LoginBindingModel model)
    {
        ClaimsIdentity ci = new ClaimsIdentity();
        // ...
        // ...
        Authentication.SignIn(ci);
        return Ok();
    }

J'ai beaucoup lu sur la sécurité sans trouver un bon échantillon avec une documentation expliquant son fonctionnement. Il semble extrêmement difficile d'implémenter une méthode de connexion simple dans une API Web.

Pourriez-vous m'expliquer pourquoi il n'y a pas de méthode de connexion dans ce modèle. Avez-vous un exemple de méthode de connexion? Et que dois-je renvoyer à l'application cliente pour authentifier la demande. Est-ce que cela fonctionne avec un jeton?

14
Bastien Vandamme

En général, vous implémentez la logique de connexion dans cette méthode et renvoyez un jeton qui sera ensuite validé à chaque appel de votre API.

Vous pouvez lire ceci pour plus d'informations

http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/

15
dariogriffo

Si vous avez créé un nouveau ASP.NET Web Application -> Web API -> Modifier l’authentification -> Individual User Accounts. Regardez App_Start -> Startup.Auth.cs.

Il devrait contenir quelque chose comme ceci:

PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
    TokenEndpointPath = new PathString("/Token"),
    Provider = new ApplicationOAuthProvider(PublicClientId),
    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
    AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
    // In production mode set AllowInsecureHttp = false
    AllowInsecureHttp = true
};

// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);

Cela signifie que vous pouvez envoyer une demande pour un jeton d'accès, exemple de demande:

 enter image description here

Vous pouvez ensuite vérifier que le jeton d'accès fonctionne:

 enter image description here

Avec ce jeton, vous pouvez maintenant accéder à toutes les ressources protégées auxquelles l'utilisateur a accès.

5
Ogglas

Si vous envisagez de créer une API pour des développeurs tiers, vous devez la sécuriser à l'aide de flux OAuth 2.0. J'ai rédigé un article détaillé comme @dariogriffo, qui implémente le flux d'informations d'identification de mot de passe du propriétaire de la ressource, qui convient à votre cas.

Vous n'avez pas besoin de créer un noeud final pour la connexion, vous allez configurer l'API à l'aide d'Owin middle-wares pour émettre des jetons porteurs OAuth aux utilisateurs lorsqu'ils appellent un noeud final tel que "/ token", puis les utilisateurs continuent à envoyer ce jeton. avec chaque demande dans l'en-tête d'autorisation. En savoir plus sur cette authentification par jeton .

4
Taiseer Joudeh

Pour les autres, une classe d'assistance, pour commencer:

namespace WeBAPITest
{



#region Using Statements:



using System.Net.Http;
using System.Collections.Generic;

using Newtonsoft.Json;



#endregion



public class HttpWebApi
{



#region Fields:



private static readonly HttpClient client = new HttpClient();



#endregion



#region Properties:



/// <summary>
/// The basr Uri.
/// </summary>
public string BaseUrl { get; set; }



/// <summary>
/// Username.
/// </summary>
protected internal string Username { get; set; }



/// <summary>
/// Password.
/// </summary>
protected internal string Password { get; set; }



/// <summary>
/// The instance of the Root Object Json Deserialised Class.
/// </summary>
internal Rootobject Authentication { get; set; }



/// <summary>
/// The Access Token from the Json Deserialised Login.
/// </summary>
public string AccessToken { get { return Authentication.access_token; } }



#endregion



public HttpWebApi(string baseurl)
{

    // Init Base Url:
    BaseUrl = baseurl;
}



/// <summary>
/// Get from the Web API.
/// </summary>
/// <param name="path">The BaseUrl + path (Uri.Host + api/Controller) to the Web API.</param>
/// <returns>A Task, when awaited, a string</returns>
public async System.Threading.Tasks.Task<string> Get(string path)
{

    if (Authentication.access_token == null)
    throw new System.Exception("Authentication is not completed.");

    // GET
    client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Authentication.access_token);
    return await client.GetStringAsync(BaseUrl + path);
}



/// <summary>
/// Logs In and populates the Authentication Variables.
/// </summary>
/// <param name="username">Your Username</param>
/// <param name="password">Your Password</param>
/// <returns>A Task, when awaited, a string</returns>
public async System.Threading.Tasks.Task<string> Login(string username, string password)
{

    // Set Username:
    Username = username;

    // Set Password:
    Password = password;

    // Conf String to Post:
    var Dic = new Dictionary<string, string>() { { "grant_type", "password" }, { "username", "" }, { "password", "" } };
    Dic["username"] = username;
    Dic["password"] = password;

    // Post to Controller:
    string auth = await Post("/Token", Dic);

    // Deserialise Response:
    Authentication = JsonConvert.DeserializeObject<Rootobject>(auth);

    return auth;
}



/// <summary>
/// Post to the Web API.
/// </summary>
/// <param name="path">The BaseUrl + path (Uri.Host + api/Controller) to the Web API.</param>
/// <param name="values">The new Dictionary<string, string> { { "value1", "x" }, { "value2", "y" } }</param>
/// <returns>A Task, when awaited, a string</returns>
public async System.Threading.Tasks.Task<string> Post(string path, Dictionary<string, string> values)
{

    // Add Access Token to the Headder:
    if (Authentication != null)
    if (Authentication.access_token != "")
        client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Authentication.access_token);

    // Encode Values:
    var content = new FormUrlEncodedContent(values);

    // Post and get Response:
    var response = await client.PostAsync(BaseUrl + path, content);

    // Return Response:
    return await response.Content.ReadAsStringAsync();
}



/// <summary>
/// Register a new User.
/// </summary>
/// <param name="username">Your Username, E-Mail</param>
/// <param name="password">Your Password</param>
/// <returns>A Task, when awaited, a string</returns>
public async System.Threading.Tasks.Task<string> Register(string username, string password)
{

    // Register: api/Account/Register
    var Dic = new Dictionary<string, string>() { { "Email", "" }, { "Password", "" }, { "ConfirmPassword", "" } };
    Dic["Email"] = username;
    Dic["Password"] = password;
    Dic["ConfirmPassword"] = password;

    return await Post("api/Account/Register", Dic);
}
}



/// <summary>
/// For Json Deserialisation.
/// </summary>
internal class Rootobject
{

/// <summary>
/// The Web Api Access Token. Gets added to the Header in each communication.
/// </summary>
public string access_token { get; set; }



/// <summary>
/// The Token Type
/// </summary>
public string token_type { get; set; }



/// <summary>
/// Expiry.
/// </summary>
public int expires_in { get; set; }



/// <summary>
/// The Username.
/// </summary>
public string userName { get; set; }



/// <summary>
/// Issued.
/// </summary>
public string issued { get; set; }



/// <summary>
/// Expiry.
/// </summary>
public string expires { get; set; }
}
}

Particulièrement conçu pour le modèle Api Web non édité par défaut dans Visual Studio.

Ensuite:

HttpWebApi httpWebApi = new HttpWebApi("http://localhost/");
await httpWebApi.Login("email", "password");

richTextBox1.AppendText(await httpWebApi.Get("api/Account/UserInfo") + Environment.NewLine);

J'espère que cela aide les autres!

0
Rusty Nail