Bagikan melalui


Autentikasi dan Otorisasi untuk SignalR Hubs

oleh Patrick Fletcher, Tom FitzMacken

Peringatan

Dokumentasi ini bukan untuk versi terbaru SignalR. Lihat ASP.NET Core SignalR.

Topik ini menjelaskan cara membatasi pengguna atau peran mana yang dapat mengakses metode hub.

Versi perangkat lunak yang digunakan dalam topik ini

Versi sebelumnya dari topik ini

Untuk informasi tentang versi SignalR yang lebih lama, lihat SignalR Versi Lama.

Pertanyaan dan komentar

Silakan tinggalkan umpan balik tentang bagaimana Anda menyukai tutorial ini dan apa yang dapat kami tingkatkan di komentar di bagian bawah halaman. Jika Anda memiliki pertanyaan yang tidak terkait langsung dengan tutorial, Anda dapat mempostingnya ke forum ASP.NET SignalR atau StackOverflow.com.

Gambaran Umum

Topik ini berisi bagian berikut:

Atribut otorisasi

SignalR menyediakan atribut Otorisasi untuk menentukan pengguna atau peran mana yang memiliki akses ke hub atau metode. Atribut ini terletak di Microsoft.AspNet.SignalR namespace layanan. Anda menerapkan atribut ke Authorize hub atau metode tertentu di hub. Saat Anda menerapkan Authorize atribut ke kelas hub, persyaratan otorisasi yang ditentukan diterapkan ke semua metode di hub. Topik ini memberikan contoh berbagai jenis persyaratan otorisasi yang dapat Anda terapkan. Authorize Tanpa atribut , klien yang terhubung dapat mengakses metode publik apa pun di hub.

Jika Anda telah menentukan peran bernama "Admin" di aplikasi web, Anda dapat menentukan bahwa hanya pengguna dalam peran tersebut yang dapat mengakses hub dengan kode berikut.

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

Atau, Anda dapat menentukan bahwa hub berisi satu metode yang tersedia untuk semua pengguna, dan metode kedua yang hanya tersedia untuk pengguna yang diautentikasi, seperti yang ditunjukkan di bawah ini.

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

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

Contoh berikut membahas skenario otorisasi yang berbeda:

  • [Authorize] – hanya pengguna yang diautentikasi
  • [Authorize(Roles = "Admin,Manager")] – hanya pengguna terautentikasi dalam peran yang ditentukan
  • [Authorize(Users = "user1,user2")] – hanya pengguna terautentikasi dengan nama pengguna yang ditentukan
  • [Authorize(RequireOutgoing=false)] – hanya pengguna terautentikasi yang dapat memanggil hub, tetapi panggilan dari server kembali ke klien tidak dibatasi oleh otorisasi, seperti, ketika hanya pengguna tertentu yang dapat mengirim pesan tetapi semua orang lain dapat menerima pesan. Properti RequireOutgoing hanya dapat diterapkan ke seluruh hub, bukan pada metode individu dalam hub. Ketika RequireOutgoing tidak diatur ke false, hanya pengguna yang memenuhi persyaratan otorisasi yang dipanggil dari server.

Memerlukan autentikasi untuk semua hub

Anda dapat memerlukan autentikasi untuk semua hub dan metode hub di aplikasi Anda dengan memanggil metode RequireAuthentication saat aplikasi dimulai. Anda dapat menggunakan metode ini ketika Anda memiliki beberapa hub dan ingin memberlakukan persyaratan autentikasi untuk semuanya. Dengan metode ini, Anda tidak dapat menentukan persyaratan untuk peran, pengguna, atau otorisasi keluar. Anda hanya dapat menentukan bahwa akses ke metode hub dibatasi untuk pengguna yang diautentikasi. Namun, Anda masih dapat menerapkan atribut Otorisasi ke hub atau metode untuk menentukan persyaratan tambahan. Persyaratan apa pun yang Anda tentukan dalam atribut ditambahkan ke persyaratan dasar autentikasi.

Contoh berikut menunjukkan file Startup yang membatasi semua metode hub untuk pengguna yang diautentikasi.

public partial class Startup {
    public void Configuration(IAppBuilder app) {
        app.MapSignalR();
        GlobalHost.HubPipeline.RequireAuthentication();
    }
}

Jika Anda memanggil RequireAuthentication() metode setelah permintaan SignalR diproses, SignalR akan memberikan InvalidOperationException pengecualian. SignalR melemparkan pengecualian ini karena Anda tidak dapat menambahkan modul ke HubPipeline setelah alur dipanggil. Contoh sebelumnya menunjukkan pemanggilan RequireAuthentication metode dalam Configuration metode yang dijalankan satu kali sebelum menangani permintaan pertama.

Otorisasi yang disesuaikan

Jika Anda perlu menyesuaikan bagaimana otorisasi ditentukan, Anda dapat membuat kelas yang berasal dari AuthorizeAttribute dan mengambil alih metode UserAuthorized . Untuk setiap permintaan, SignalR memanggil metode ini untuk menentukan apakah pengguna berwenang untuk menyelesaikan permintaan. Dalam metode yang ditimpa, Anda memberikan logika yang diperlukan untuk skenario otorisasi Anda. Contoh berikut menunjukkan cara menerapkan otorisasi melalui identitas berbasis klaim.

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

Meneruskan informasi autentikasi ke klien

Anda mungkin perlu menggunakan informasi autentikasi dalam kode yang berjalan pada klien. Anda meneruskan informasi yang diperlukan saat memanggil metode pada klien. Misalnya, metode aplikasi obrolan dapat diteruskan sebagai parameter nama pengguna orang yang memposting pesan, seperti yang ditunjukkan di bawah ini.

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

Atau, Anda dapat membuat objek untuk mewakili informasi autentikasi dan meneruskan objek tersebut sebagai parameter, seperti yang ditunjukkan di bawah ini.

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

Anda tidak boleh meneruskan id koneksi satu klien ke klien lain, karena pengguna berbahaya dapat menggunakannya untuk meniru permintaan dari klien tersebut.

Opsi autentikasi untuk klien .NET

Saat Anda memiliki klien .NET, seperti aplikasi konsol, yang berinteraksi dengan hub yang terbatas pada pengguna yang diautentikasi, Anda dapat meneruskan kredensial autentikasi di cookie, header koneksi, atau sertifikat. Contoh di bagian ini menunjukkan cara menggunakan metode berbeda tersebut untuk mengautentikasi pengguna. Mereka bukan aplikasi SignalR yang berfungsi penuh. Untuk informasi selengkapnya tentang klien .NET dengan SignalR, lihat Panduan API Hubs - Klien .NET.

Ketika klien .NET Anda berinteraksi dengan hub yang menggunakan Autentikasi Formulir ASP.NET, Anda harus mengatur cookie autentikasi secara manual pada koneksi. Anda menambahkan cookie ke CookieContainer properti pada objek HubConnection . Contoh berikut menunjukkan aplikasi konsol yang mengambil cookie autentikasi dari halaman web dan menambahkan cookie tersebut ke koneksi.

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

Aplikasi konsol memposting kredensial ke www.contoso.com/RemoteLogin yang dapat merujuk ke halaman kosong yang berisi file code-behind berikut.

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

Autentikasi Windows

Saat menggunakan autentikasi Windows, Anda dapat meneruskan kredensial pengguna saat ini dengan menggunakan properti DefaultCredentials . Anda mengatur kredensial untuk koneksi ke nilai DefaultCredentials.

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

Header koneksi

Jika aplikasi Anda tidak menggunakan cookie, Anda dapat meneruskan informasi pengguna di header koneksi. Misalnya, Anda dapat meneruskan token di header koneksi.

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

Kemudian, di hub, Anda akan memverifikasi token pengguna.

Sertifikat

Anda dapat meneruskan sertifikat klien untuk memverifikasi pengguna. Anda menambahkan sertifikat saat membuat koneksi. Contoh berikut hanya memperlihatkan cara menambahkan sertifikat klien ke koneksi; ini tidak menampilkan aplikasi konsol lengkap. Ini menggunakan kelas X509Certificate yang menyediakan beberapa cara berbeda untuk membuat sertifikat.

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