Проверка подлинности и авторизация для концентраторов SignalR
Патрик Флетчер (Patrick Fletcher), Том ФитцМаккен (Tom FitzMacken)
Предупреждение
Эта документация не подходит для последней версии SignalR. Ознакомьтесь с ASP.NET Core SignalR.
В этом разделе описывается, как ограничить доступ пользователей или ролей к методам концентратора.
Версии программного обеспечения, используемые в этом разделе
- Visual Studio 2013
- .NET 4.5
- SignalR версии 2
Предыдущие версии этого раздела
Сведения о более ранних версиях SignalR см. в разделе Старые версии SignalR.
Вопросы и комментарии
Оставьте отзыв о том, как вам понравилось это руководство и что мы могли бы улучшить в комментариях в нижней части страницы. Если у вас есть вопросы, которые не связаны непосредственно с руководством, вы можете опубликовать их на форуме ASP.NET SignalR или StackOverflow.com.
Общие сведения
Этот раздел состоит из следующих подразделов.
Атрибут Authorize
SignalR предоставляет атрибут Authorize , чтобы указать, какие пользователи или роли имеют доступ к концентратору или методу. Этот атрибут находится в Microsoft.AspNet.SignalR
пространстве имен . Атрибут применяется Authorize
к концентратору или определенным методам в концентраторе. При применении атрибута Authorize
к классу концентратора указанное требование авторизации применяется ко всем методам в концентраторе. В этом разделе приведены примеры различных типов требований к авторизации, которые можно применить. Без атрибута Authorize
подключенный клиент может получить доступ к любому общедоступному методу в концентраторе.
Если в веб-приложении определена роль с именем "Администратор", можно указать, что только пользователи с этой ролью могут получить доступ к концентратору с помощью следующего кода.
[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)]
— вызывать концентратор могут только пользователи, прошедшие проверку подлинности, но вызовы с сервера обратно к клиентам не ограничиваются авторизацией, например, когда только некоторые пользователи могут отправлять сообщение, но все остальные могут получать сообщение. Свойство RequireOutgoing можно применить только ко всему концентратору, а не к отдельным методам в концентраторе. Если параметр RequireOutgoing не имеет значение false, с сервера вызываются только пользователи, соответствующие требованиям авторизации.
Требовать проверку подлинности для всех центров
Вы можете требовать проверку подлинности для всех концентраторов и методов концентраторов в приложении, вызвав метод RequireAuthentication при запуске приложения. Этот метод можно использовать, если у вас есть несколько концентраторов и требуется применить требование проверки подлинности для всех них. При использовании этого метода невозможно указать требования к роли, пользователю или исходящей авторизации. Можно указать только, что доступ к методам концентратора ограничен пользователями, прошедшими проверку подлинности. Однако вы по-прежнему можете применить атрибут Authorize к концентраторам или методам, чтобы указать дополнительные требования. Любое требование, указанное в атрибуте, добавляется к базовому требованию проверки подлинности.
В следующем примере показан файл запуска, который ограничивает все методы концентратора для пользователей, прошедших проверку подлинности.
public partial class Startup {
public void Configuration(IAppBuilder app) {
app.MapSignalR();
GlobalHost.HubPipeline.RequireAuthentication();
}
}
Если вызвать RequireAuthentication()
метод после обработки запроса SignalR, SignalR вызовет InvalidOperationException
исключение. SignalR создает это исключение, так как после вызова конвейера невозможно добавить модуль в HubPipeline. В предыдущем примере показан вызов RequireAuthentication
метода в методе Configuration
, который выполняется один раз перед обработкой первого запроса.
Настраиваемая авторизация
Если необходимо настроить способ определения авторизации, можно создать класс, производный от AuthorizeAttribute
, и переопределить метод UserAuthorized . Для каждого запроса SignalR вызывает этот метод, чтобы определить, авторизован ли пользователь на выполнение запроса. В переопределенном методе вы предоставляете необходимую логику для сценария авторизации. В следующем примере показано, как применить авторизацию с помощью удостоверения на основе утверждений.
[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
};
}
}
Никогда не следует передавать идентификатор подключения одного клиента другим клиентам, так как злоумышленник может использовать его для имитации запроса от этого клиента.
Варианты проверки подлинности для клиентов .NET
Если у вас есть клиент .NET, например консольное приложение, которое взаимодействует с концентратором, который ограничен пользователями, прошедшими проверку подлинности, вы можете передать учетные данные проверки подлинности в файле cookie, заголовке подключения или сертификате. В примерах в этом разделе показано, как использовать эти различные методы для проверки подлинности пользователя. Это не полностью функциональные приложения SignalR. Дополнительные сведения о клиентах .NET с SignalR см. в разделе Руководство по API концентраторов — клиент .NET.
Куки-файл
Когда клиент .NET взаимодействует с концентратором, использующим ASP.NET проверку подлинности с помощью форм, необходимо вручную задать файл cookie проверки подлинности для подключения. Файл cookie добавляется в CookieContainer
свойство объекта HubConnection . В следующем примере показано консольное приложение, которое получает файл cookie проверки подлинности с веб-страницы и добавляет его в подключение.
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;
}
}
}
Консольное приложение отправляет учетные данные в www.contoso.com/RemoteLogin который может ссылаться на пустую страницу, содержащую следующий файл кода программной части.
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
При использовании проверка подлинности Windows можно передать учетные данные текущего пользователя с помощью свойства DefaultCredentials. Присвойте учетным данным для подключения значение DefaultCredentials.
class Program
{
static void Main(string[] args)
{
var connection = new HubConnection("http://www.contoso.com/");
connection.Credentials = CredentialCache.DefaultCredentials;
connection.Start().Wait();
}
}
Заголовок подключения
Если приложение не использует файлы cookie, вы можете передать сведения о пользователе в заголовке подключения. Например, можно передать маркер в заголовке подключения.
class Program
{
static void Main(string[] args)
{
var connection = new HubConnection("http://www.contoso.com/");
connection.Headers.Add("myauthtoken", /* token data */);
connection.Start().Wait();
}
}
Затем в центре необходимо проверить маркер пользователя.
Сертификат
Вы можете передать сертификат клиента для проверки пользователя. Сертификат добавляется при создании подключения. В следующем примере показано, как добавить сертификат клиента к подключению. В нем не отображается полное консольное приложение. Он использует класс X509Certificate , который предоставляет несколько различных способов создания сертификата.
class Program
{
static void Main(string[] args)
{
var connection = new HubConnection("http://www.contoso.com/");
connection.AddClientCertificate(X509Certificate.CreateFromCertFile("MyCert.cer"));
connection.Start().Wait();
}
}