احراز هویت و مجوز برای SignalR Hub

پنجشنبه 2 دی 1395

در مقاله قصد داریم که چگونگی محدود کردن دسترسی کاربران و یا نقش ها را به متد های هاب بررسی کنیم.که در زیر به توضیح آن میپردازیم.

احراز هویت و مجوز برای  SignalR Hub

ورژن نرم افزار هایی که ما در این مقاله استفاده میکنیم :

.• Visual Studio 2013

• .NET 4.5

•  SignalR نسخه 2

صفت Authorize :

SignalR صفت Authorize برای مشخص کردن سطح دسترسی کاربران و نقش ها به متد های هاب تعیین کرده است. این صفت در فضای نام  Microsoft.AspNet.SignalR قرار گرفته است.

شما از صفت Authorize  برای یک هاب یا قسمتی از متد هاب میتوانید استفاده کنید.

 زمانی که شما درخواست صفت Authorize را برای یک کلاس هاب میکنید، مجوز مورد نیاز به تمام متدهای این کلاس هاب اعمال میشود.

بدون صفت Authorize ،یک کلاینت میتواند به تمام متد های عمومی دسترسی داشته باشید.

اگر شما نقشی به نام Admin در  web application خود تعریف کرده باشید میتوانید اجازه دسترسی به هاب را کاربرانی بدهید که نقش ادمین دارند بدهید.

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

یا ، شما میتوانید مشخص کنید که یک هاب شامل  یک متد است که برای تمامی کاربران در دسترس است و متد دوم آن نیازمند احراز هویت میباشد.

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

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

سناریو های مختلف یک احراز هویت :

• [Authorize] - فقط کاربران احراز هویت شده

• [Authorize(Roles = "Admin,Manager")] -  فقط کاربران احراز هویت شده در نقش های تعیین شده

• [Authorize(Users = "user1,user2")] -  فقط کاربران احراز هویت شده در نام های تعیین شده

• [Authorize(RequireOutgoing=false)] - تنها کاربران احراز هویت شده میتوانند ،در هاب شرکت (Invoke)کنند . 

صفت RequireOutgoing میتواند فقط در هاب استفاده شود. هنگامی که RequireOutgoing به صورت false قرار گیرد، فقط کاربرانی که از سمت سرور دسترسی دارند ، اجازه ی دسترسی دارند.

نیاز به احراز هویت برای همه مراکز :

شما میتوانید توسط RequireAuthentication در برنامه خود  تمام هاب و متدهای آن هنگام start پروژه خود نیازمند احراز هویت کنید.

شما ممکن است از این متد هنگامی که شما چند هاب دارید استفاده کنید و بخواهید که مجبور کنید به احراز هویت برای تمام آنها.

با این متد،شما نمیتوانید الزامات مورد نیاز برای نقش، کاربر، و یا اجازه خروجی مشخص کنید.شما فقط میتوانید سطح دسترسی به متد های هاب را برای  کاربران منحصر کنید.

هرچند هنوز شما میتوانید صفت Authorize را برای هاب یا متد ها به عنوان نیازمندی استفاده کنید.

هر نیازمندی که شما در یک صفت مشخص میکنیددر نیازمندی های پایه( basic requirement ) احراز هویت اضافه میشود.

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

اگر شما متد () RequireAuthentication را فراخوانی کنید بعد از یک درخواست SignalR پردازش شده، SignalR یک  InvalidOperationException exception را پرتاب میکند.

SignalR این خطا را پرتاب میکند به این دلیل که شما نمیتوانید یک ماژول به HubPipeline  بعد از آنکه pipeline درگیر(invoke) شده باشد اضافه کنید.

مثال قبل فراخوانی متد RequireAuthentication در متد Configuration را نشان میدهد که یک بار در اولین درخواست اجرا شده بود.

شخصی سازی احراز هویت :

اگرشما نیاز به شخصی سازی احراز هویت دارید باید یک کلاس از AuthorizeAttribute مشتق کنید  و متد  UserAuthorized را بازنویسی کنید.

برای هر درخواست ، SignalR این متد را برای تعریف اینکه چگونه کاربر به کل درخواست دسترسی داشته باشد،درگیر میکند.

در بازنویسی متد،منطق لازم برای  سناریو احراز هویت خود را تهیه کنید.

مثال زیر از یک claims-based identity است.

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

اطلاعات احراز هویت خود را به کلاینت بفرستید :

ما ممکن است به اطلاعات احراز هویت در سمت کلاینت هنگام اجرای کد نیاز داشته باشید.

شما اطلاعات ضروری را هنگام فراخوانی متد به سمت کلاینت پاس دهید..برای مثال ، یک برنامه چت میتواند نام کاربری را از طریق ارسال پیام به کاربر ارسال کند.

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

یا شما میتوانید یک شی برای نشان دادن اطلاعات احراز هویت بسازید و شی را به عنوان پارامتر ارسال کنید.

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

شما هرگز نباید ID اتصال یک کلاینت را به کلاینت دیگر بدهید. به عنوان یک کاربر مخرب میتواند آن را به تقلید از یک درخواست از مشتری استفاده کند.

ویژگی های احراز هویت برای کلاینت های NET.  :

هنگامی که شما یک کلاینت NET. دارید ، شامل یک console app ، که با یک hub که کاربران را با احراز هویت محدود کرده است ،در تعامل است ، شما میتوانید مدارک احراز هویت را در یک کوکی ،  connection header یا یک گواهی نامه ارسال کنید.

مثال این قسمت چگونگی استفاده از این متد های مختلف برای احراز هویت یک کاربر را  نشان میدهد. برنامه های SignalR به طور کامل کاربردی نیست.

کوکی (Cookie):

هنگامی که کلاینت NET. شما با  یک هاب که از ASP.NET Forms Authentication استفاده میکند در تعامل است، شما نیاز به set کردن کوکی احرازهویت به صورت دستی میباشید.

شما کوکی را به صفت CookieContainer روی شی  HubConnection اضافه میکنید.

مثال زیر یک برنامه Console است که کوکی اهراز هویت را  از یک صفحه بازیابی میکند.

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

برنامه Console اعتبارنامه را به www.contoso.com/RemoteLogin ارسال میکند که میتواند به یک صفحه خالی ارجاع شده باشد که شامل فایل code-behind  زیر است :

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 authentication :

هنگامی که از  Windows authentication استفاده میکنیم ، شما میتوانید اعتبار نامه ی کاربر جاری را با استفاده از صفت  DefaultCredentials ارسال کنید.

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

Connection header :

اگر برنامه شما از cookie ها استفاده نمیکند، شما میتوانید اطلاعات کاربر را در Connection header ارسال کنید. برای مثال شما میتوانید یک Token در Connection header ارسال کنید:

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

گواهی نامه :

شما میتوانید یک گواهی نامه مشتری ( client certificate ) برای صحت کاربر ارسال کنید. شما گواهی نامه را هنگامی اتصال در حال ساخت است ، اضافه کنید.

مثال زیر نشان میدهد که چگونه یک گواهی نامه کلاینت به connection اضافه میشود.

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

آموزش سی شارپ

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان
  • C#.net
  • 2k بازدید
  • 6 تشکر

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید