Authentification et autorisation pour SignalR Hubs
par Patrick Fletcher, Tom FitzMacken
Avertissement
Cette documentation ne concerne pas la dernière version de SignalR. Jetez un coup d’œil à ASP.NET Core SignalR.
Cette rubrique explique comment restreindre les utilisateurs ou rôles qui peuvent accéder aux méthodes hub.
Versions logicielles utilisées dans cette rubrique
- Visual Studio 2013
- .NET 4.5
- SignalR version 2
Versions précédentes de cette rubrique
Pour plus d’informations sur les versions antérieures de SignalR, consultez Versions antérieures de SignalR.
Questions et commentaires
Laissez des commentaires sur la façon dont vous avez aimé ce tutoriel et ce que nous pourrions améliorer dans les commentaires en bas de la page. Si vous avez des questions qui ne sont pas directement liées au tutoriel, vous pouvez les publier sur le forum ASP.NET SignalR ou StackOverflow.com.
Vue d’ensemble
Cette rubrique contient les sections suivantes :
Autoriser l’attribut
SignalR fournit l’attribut Authorize pour spécifier quels utilisateurs ou rôles ont accès à un hub ou à une méthode. Cet attribut se trouve dans l’espace de Microsoft.AspNet.SignalR
noms . Vous appliquez l’attribut Authorize
à un hub ou à des méthodes particulières dans un hub. Lorsque vous appliquez l’attribut Authorize
à une classe hub, l’exigence d’autorisation spécifiée est appliquée à toutes les méthodes du hub. Cette rubrique fournit des exemples des différents types d’exigences d’autorisation que vous pouvez appliquer. Sans l’attribut Authorize
, un client connecté peut accéder à n’importe quelle méthode publique sur le hub.
Si vous avez défini un rôle nommé « Administration » dans votre application web, vous pouvez spécifier que seuls les utilisateurs de ce rôle peuvent accéder à un hub avec le code suivant.
[Authorize(Roles = "Admin")]
public class AdminAuthHub : Hub
{
}
Vous pouvez également spécifier qu’un hub contient une méthode disponible pour tous les utilisateurs et une deuxième méthode uniquement disponible pour les utilisateurs authentifiés, comme indiqué ci-dessous.
public class SampleHub : Hub
{
public void UnrestrictedSend(string message){ . . . }
[Authorize]
public void AuthenticatedSend(string message){ . . . }
}
Les exemples suivants concernent différents scénarios d’autorisation :
[Authorize]
– uniquement les utilisateurs authentifiés[Authorize(Roles = "Admin,Manager")]
: uniquement les utilisateurs authentifiés dans les rôles spécifiés[Authorize(Users = "user1,user2")]
: uniquement les utilisateurs authentifiés avec les noms d’utilisateur spécifiés[Authorize(RequireOutgoing=false)]
: seuls les utilisateurs authentifiés peuvent appeler le hub, mais les appels du serveur vers les clients ne sont pas limités par l’autorisation, par exemple, lorsque seuls certains utilisateurs peuvent envoyer un message, mais que tous les autres peuvent recevoir le message. La propriété RequireOutgoing ne peut être appliquée qu’à l’ensemble du hub, et non à des méthodes individuelles au sein du hub. Lorsque RequireOutgoing n’est pas défini sur false, seuls les utilisateurs qui répondent à l’exigence d’autorisation sont appelés à partir du serveur.
Exiger l’authentification pour tous les hubs
Vous pouvez exiger l’authentification pour tous les hubs et méthodes hub de votre application en appelant la méthode RequireAuthentication au démarrage de l’application. Vous pouvez utiliser cette méthode lorsque vous avez plusieurs hubs et que vous souhaitez appliquer une exigence d’authentification pour tous ces hubs. Avec cette méthode, vous ne pouvez pas spécifier les exigences relatives au rôle, à l’utilisateur ou à l’autorisation sortante. Vous pouvez uniquement spécifier que l’accès aux méthodes hub est limité aux utilisateurs authentifiés. Toutefois, vous pouvez toujours appliquer l’attribut Authorize à des hubs ou à des méthodes pour spécifier des exigences supplémentaires. Toute exigence que vous spécifiez dans un attribut est ajoutée à l’exigence de base de l’authentification.
L’exemple suivant montre un fichier de démarrage qui limite toutes les méthodes hub aux utilisateurs authentifiés.
public partial class Startup {
public void Configuration(IAppBuilder app) {
app.MapSignalR();
GlobalHost.HubPipeline.RequireAuthentication();
}
}
Si vous appelez la RequireAuthentication()
méthode après le traitement d’une requête SignalR, SignalR lève une InvalidOperationException
exception. SignalR lève cette exception, car vous ne pouvez pas ajouter un module à HubPipeline après l’appel du pipeline. L’exemple précédent montre l’appel de la RequireAuthentication
méthode dans la Configuration
méthode qui est exécutée une fois avant de gérer la première requête.
Autorisation personnalisée
Si vous devez personnaliser la façon dont l’autorisation est déterminée, vous pouvez créer une classe qui dérive de AuthorizeAttribute
et remplace la méthode UserAuthorized . Pour chaque requête, SignalR appelle cette méthode pour déterminer si l’utilisateur est autorisé à effectuer la demande. Dans la méthode substituée, vous fournissez la logique nécessaire pour votre scénario d’autorisation. L’exemple suivant montre comment appliquer l’autorisation par le biais d’une identité basée sur les revendications.
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class AuthorizeClaimsAttribute : AuthorizeAttribute
{
protected override bool UserAuthorized(System.Security.Principal.IPrincipal user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
var principal = user as ClaimsPrincipal;
if (principal != null)
{
Claim authenticated = principal.FindFirst(ClaimTypes.Authentication);
if (authenticated != null && authenticated.Value == "true")
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
Transmettre des informations d’authentification aux clients
Vous devrez peut-être utiliser les informations d’authentification dans le code qui s’exécute sur le client. Vous transmettez les informations requises lors de l’appel des méthodes sur le client. Par exemple, une méthode d’application de conversation peut passer en tant que paramètre le nom d’utilisateur de la personne qui publie un message, comme indiqué ci-dessous.
public Task SendChatMessage(string message)
{
string name;
var user = Context.User;
if (user.Identity.IsAuthenticated)
{
name = user.Identity.Name;
}
else
{
name = "anonymous";
}
return Clients.All.addMessageToPage(name, message);
}
Vous pouvez également créer un objet pour représenter les informations d’authentification et passer cet objet en tant que paramètre, comme indiqué ci-dessous.
public class SampleHub : Hub
{
public override Task OnConnected()
{
return Clients.All.joined(GetAuthInfo());
}
protected object GetAuthInfo()
{
var user = Context.User;
return new
{
IsAuthenticated = user.Identity.IsAuthenticated,
IsAdmin = user.IsInRole("Admin"),
UserName = user.Identity.Name
};
}
}
Vous ne devez jamais transmettre l’ID de connexion d’un client à d’autres clients, car un utilisateur malveillant peut l’utiliser pour imiter une demande de ce client.
Options d’authentification pour les clients .NET
Lorsque vous disposez d’un client .NET, tel qu’une application console, qui interagit avec un hub limité aux utilisateurs authentifiés, vous pouvez transmettre les informations d’identification d’authentification dans un cookie, l’en-tête de connexion ou un certificat. Les exemples de cette section montrent comment utiliser ces différentes méthodes pour l’authentification d’un utilisateur. Il ne s’agit pas d’applications SignalR entièrement fonctionnelles. Pour plus d’informations sur les clients .NET avec SignalR, consultez Guide de l’API Hubs - Client .NET.
Cookie
Lorsque votre client .NET interagit avec un hub qui utilise ASP.NET l’authentification par formulaire, vous devez définir manuellement le cookie d’authentification sur la connexion. Vous ajoutez le cookie à la CookieContainer
propriété sur l’objet HubConnection . L’exemple suivant montre une application console qui récupère un cookie d’authentification à partir d’une page web et ajoute ce cookie à la connexion.
class Program
{
static void Main(string[] args)
{
var connection = new HubConnection("http://www.contoso.com/");
Cookie returnedCookie;
Console.Write("Enter user name: ");
string username = Console.ReadLine();
Console.Write("Enter password: ");
string password = Console.ReadLine();
var authResult = AuthenticateUser(username, password, out returnedCookie);
if (authResult)
{
connection.CookieContainer = new CookieContainer();
connection.CookieContainer.Add(returnedCookie);
Console.WriteLine("Welcome " + username);
}
else
{
Console.WriteLine("Login failed");
}
}
private static bool AuthenticateUser(string user, string password, out Cookie authCookie)
{
var request = WebRequest.Create("https://www.contoso.com/RemoteLogin") as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.CookieContainer = new CookieContainer();
var authCredentials = "UserName=" + user + "&Password=" + password;
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(authCredentials);
request.ContentLength = bytes.Length;
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
}
using (var response = request.GetResponse() as HttpWebResponse)
{
authCookie = response.Cookies[FormsAuthentication.FormsCookieName];
}
if (authCookie != null)
{
return true;
}
else
{
return false;
}
}
}
L’application console publie les informations d’identification dans www.contoso.com/RemoteLogin qui peut faire référence à une page vide contenant le fichier code-behind suivant.
using System;
using System.Web.Security;
namespace SignalRWithConsoleChat
{
public partial class RemoteLogin : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string username = Request["UserName"];
string password = Request["Password"];
bool result = Membership.ValidateUser(username, password);
if (result)
{
FormsAuthentication.SetAuthCookie(username, false);
}
}
}
}
Authentification Windows
Lorsque vous utilisez Authentification Windows, vous pouvez transmettre les informations d’identification de l’utilisateur actuel à l’aide de la propriété DefaultCredentials. Vous définissez les informations d’identification de la connexion sur la valeur de DefaultCredentials.
class Program
{
static void Main(string[] args)
{
var connection = new HubConnection("http://www.contoso.com/");
connection.Credentials = CredentialCache.DefaultCredentials;
connection.Start().Wait();
}
}
En-tête de connexion
Si votre application n’utilise pas de cookies, vous pouvez transmettre les informations utilisateur dans l’en-tête de connexion. Par exemple, vous pouvez passer un jeton dans l’en-tête de connexion.
class Program
{
static void Main(string[] args)
{
var connection = new HubConnection("http://www.contoso.com/");
connection.Headers.Add("myauthtoken", /* token data */);
connection.Start().Wait();
}
}
Ensuite, dans le hub, vous devez vérifier le jeton de l’utilisateur.
Certificat
Vous pouvez passer un certificat client pour vérifier l’utilisateur. Vous ajoutez le certificat lors de la création de la connexion. L’exemple suivant montre uniquement comment ajouter un certificat client à la connexion . elle n’affiche pas l’application console complète. Il utilise la classe X509Certificate qui fournit plusieurs façons différentes de créer le certificat.
class Program
{
static void Main(string[] args)
{
var connection = new HubConnection("http://www.contoso.com/");
connection.AddClientCertificate(X509Certificate.CreateFromCertFile("MyCert.cer"));
connection.Start().Wait();
}
}