Dela via


Autentisering och auktorisering för SignalR Hubs (SignalR 1.x)

av Patrick Fletcher, Tom FitzMacken

Varning

Den här dokumentationen gäller inte för den senaste versionen av SignalR. Ta en titt på ASP.NET Core SignalR.

Det här avsnittet beskriver hur du begränsar vilka användare eller roller som kan komma åt hubbmetoder.

Översikt

Det här avsnittet innehåller följande avsnitt:

Auktorisera attribut

SignalR tillhandahåller attributet Auktorisera för att ange vilka användare eller roller som har åtkomst till en hubb eller metod. Det här attributet finns i Microsoft.AspNet.SignalR namnområdet. Du använder Authorize attributet för antingen en hubb eller vissa metoder i en hubb. När du tillämpar attributet på Authorize en hubbklass tillämpas det angivna auktoriseringskravet på alla metoder i hubben. De olika typerna av auktoriseringskrav som du kan tillämpa visas nedan. Authorize Utan attributet är alla offentliga metoder på hubben tillgängliga för en klient som är ansluten till hubben.

Om du har definierat en roll med namnet "Admin" i webbprogrammet kan du ange att endast användare i den rollen kan komma åt en hubb med följande kod.

[Authorize(Roles = "Admin")] 
public class AdminAuthHub : Hub 
{ 
}

Eller så kan du ange att en hubb innehåller en metod som är tillgänglig för alla användare och en andra metod som endast är tillgänglig för autentiserade användare enligt nedan.

public class SampleHub : Hub 
{ 
    public void UnrestrictedSend(string message){ . . . } 

    [Authorize] 
    public void AuthenticatedSend(string message){ . . . } 
}

Följande exempel tar upp olika auktoriseringsscenarier:

  • [Authorize] – endast autentiserade användare
  • [Authorize(Roles = "Admin,Manager")] – endast autentiserade användare i de angivna rollerna
  • [Authorize(Users = "user1,user2")] – endast autentiserade användare med angivna användarnamn
  • [Authorize(RequireOutgoing=false)] – Endast autentiserade användare kan anropa hubben, men anrop från servern tillbaka till klienter begränsas inte av auktorisering, till exempel när endast vissa användare kan skicka ett meddelande, men alla andra kan ta emot meddelandet. Egenskapen RequireOutgoing kan bara tillämpas på hela hubben, inte på enskilda metoder i hubben. När RequireOutgoing inte är inställt på false anropas endast användare som uppfyller auktoriseringskravet från servern.

Kräv autentisering för alla hubbar

Du kan kräva autentisering för alla hubbar och hubbmetoder i ditt program genom att anropa metoden RequireAuthentication när programmet startar. Du kan använda den här metoden när du har flera hubbar och vill framtvinga ett autentiseringskrav för alla. Med den här metoden kan du inte ange roll, användare eller utgående auktorisering. Du kan bara ange att åtkomsten till hubbmetoderna är begränsad till autentiserade användare. Du kan dock fortfarande använda attributet Auktorisera för hubbar eller metoder för att ange ytterligare krav. Alla krav som du anger i attribut tillämpas utöver det grundläggande kravet på autentisering.

I följande exempel visas en Global.asax-fil som begränsar alla hubbmetoder till autentiserade användare.

public class Global : HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.MapHubs();
        GlobalHost.HubPipeline.RequireAuthentication();
    }
}

Om du anropar RequireAuthentication() metoden efter att en SignalR-begäran har bearbetats utlöser SignalR ett InvalidOperationException undantag. Det här undantaget genereras eftersom du inte kan lägga till en modul i HubPipeline när pipelinen har anropats. I föregående exempel visas anrop av RequireAuthentication metoden i metoden Application_Start som körs en gång innan den första begäran hanteras.

Anpassad auktorisering

Om du behöver anpassa hur auktorisering fastställs kan du skapa en klass som härleds från AuthorizeAttribute och åsidosätta metoden Användarauktoriserat . Den här metoden anropas för varje begäran för att avgöra om användaren har behörighet att slutföra begäran. I den åsidosatta metoden anger du den logik som krävs för ditt auktoriseringsscenario. I följande exempel visas hur du framtvingar auktorisering via anspråksbaserad identitet.

[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 = (ClaimsPrincipal)user;

        if (principal != null)
        {
            Claim authenticated = principal.FindFirst(ClaimTypes.Authentication);
            return authenticated.Value == "true" ? true : false;
        }
        else
        {
            return false;
        }
    }
}

Skicka autentiseringsinformation till klienter

Du kan behöva använda autentiseringsinformation i koden som körs på klienten. Du skickar nödvändig information när du anropar metoderna i klienten. En chattprogrammetod kan till exempel skicka användarnamnet för den person som publicerar ett meddelande som en parameter som visas nedan.

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);
}

Eller så kan du skapa ett objekt som representerar autentiseringsinformationen och skicka objektet som en parameter, enligt nedan.

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
        };
    }
}

Du bör aldrig skicka en klients anslutnings-ID till andra klienter, eftersom en obehörig användare kan använda det för att efterlikna en begäran från den klienten.

Autentiseringsalternativ för .NET-klienter

När du har en .NET-klient, till exempel en konsolapp, som interagerar med en hubb som är begränsad till autentiserade användare, kan du skicka autentiseringsuppgifterna i en cookie, anslutningshuvudet eller ett certifikat. Exemplen i det här avsnittet visar hur du använder dessa olika metoder för att autentisera en användare. De är inte fullt fungerande SignalR-appar. Mer information om .NET-klienter med SignalR finns i Hubs API Guide – .NET-klient.

När .NET-klienten interagerar med en hubb som använder ASP.NET formulärautentisering måste du manuellt ange autentiseringscookien för anslutningen. Du lägger till cookien i CookieContainer egenskapen på HubConnection-objektet . I följande exempel visas en konsolapp som hämtar en autentiseringscookie från en webbsida och lägger till cookien i anslutningen. URL:en https://www.contoso.com/RemoteLogin i exemplet pekar på en webbsida som du skulle behöva skapa. Sidan hämtar det publicerade användarnamnet och lösenordet och försöker logga in användaren med autentiseringsuppgifterna.

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;
        }
    }
}

Konsolappen publicerar autentiseringsuppgifterna till www.contoso.com/RemoteLogin, som kan hänvisa till en tom sida som innehåller följande kod-bakom-fil.

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);
            }
        }
    }
}

Windows-autentisering

När du använder Windows-autentisering kan du skicka den aktuella användarens autentiseringsuppgifter med egenskapen DefaultCredentials . Du anger autentiseringsuppgifterna för anslutningen till värdet av DefaultCredentials.

class Program
{
    static void Main(string[] args)
    {
        var connection = new HubConnection("http://www.contoso.com/");
        connection.Credentials = CredentialCache.DefaultCredentials;
        connection.Start().Wait();
    }
}

Anslutningshuvudrad

Om ditt program inte använder cookies kan du skicka användarinformation i anslutningshuvudet. Du kan till exempel skicka en token i anslutningshuvudet.

class Program
{
    static void Main(string[] args)
    {
        var connection = new HubConnection("http://www.contoso.com/");
        connection.Headers.Add("myauthtoken", /* token data */);
        connection.Start().Wait();
    }
}

I hubben verifierar du sedan användarens token.

Certifikat

Du kan skicka ett klientcertifikat för att verifiera användaren. Du lägger till certifikatet när du skapar anslutningen. I följande exempel visas bara hur du lägger till ett klientcertifikat i anslutningen. den visar inte den fullständiga konsolappen. Den använder klassen X509Certificate som tillhandahåller flera olika sätt att skapa certifikatet.

class Program
{
    static void Main(string[] args)
    {
        var connection = new HubConnection("http://www.contoso.com/");
        connection.AddClientCertificate(X509Certificate.CreateFromCertFile("MyCert.cer"));
        connection.Start().Wait();
    }
}