SignalR 허브에 대한 인증 및 권한 부여(SignalR 1.x)
작성자: Patrick Fletcher, Tom FitzMacken
경고
이 설명서는 최신 버전의 SignalR용이 아닙니다. ASP.NET Core SignalR을 살펴보세요.
이 항목에서는 허브 메서드에 액세스할 수 있는 사용자 또는 역할을 제한하는 방법을 설명합니다.
개요
이 항목에는 다음과 같은 섹션이 포함되어 있습니다.
권한 부여 특성
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 특성을 적용하여 추가 요구 사항을 지정할 수 있습니다. 특성에 지정한 모든 요구 사항은 인증의 기본 요구 사항 외에도 적용됩니다.
다음 예제에서는 모든 허브 메서드를 인증된 사용자로 제한하는 Global.asax 파일을 보여 줍니다.
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapHubs();
GlobalHost.HubPipeline.RequireAuthentication();
}
}
SignalR 요청이 RequireAuthentication()
처리된 후 메서드를 호출하면 SignalR에서 예외가 InvalidOperationException
throw됩니다. 파이프라인이 호출된 후에는 HubPipeline에 모듈을 추가할 수 없으므로 이 예외가 throw됩니다. 이전 예제에서는 첫 번째 요청을 처리하기 전에 한 번 실행되는 메서드에서 Application_Start
메서드를 호출 RequireAuthentication
하는 방법을 보여 있습니다.
사용자 지정된 권한 부여
권한 부여가 결정되는 방법을 사용자 지정해야 하는 경우 에서 AuthorizeAttribute
파생되는 클래스를 만들고 UserAuthorized 메서드를 재정의할 수 있습니다. 각 요청에 대해 이 메서드가 호출되어 사용자가 요청을 완료할 수 있는 권한이 있는지 여부를 확인합니다. 재정의된 메서드에서는 권한 부여 시나리오에 필요한 논리를 제공합니다. 다음 예제에서는 클레임 기반 ID를 통해 권한 부여를 적용하는 방법을 보여줍니다.
[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;
}
}
}
클라이언트에 인증 정보 전달
클라이언트에서 실행되는 코드에서 인증 정보를 사용해야 할 수 있습니다. 클라이언트에서 메서드를 호출할 때 필요한 정보를 전달합니다. 예를 들어 채팅 애플리케이션 메서드는 아래와 같이 메시지를 게시하는 사람의 사용자 이름을 매개 변수로 전달할 수 있습니다.
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 클라이언트가 있는 경우 쿠키, 연결 헤더 또는 인증서에 인증 자격 증명을 전달할 수 있습니다. 이 섹션의 예제에서는 사용자를 인증하기 위해 이러한 다양한 메서드를 사용하는 방법을 보여 줍니다. 완전한 기능을 갖춘 SignalR 앱이 아닙니다. SignalR을 사용하는 .NET 클라이언트에 대한 자세한 내용은 허브 API 가이드 - .NET 클라이언트를 참조하세요.
쿠키
.NET 클라이언트가 ASP.NET Forms 인증을 사용하는 허브와 상호 작용하는 경우 연결에서 인증 쿠키를 수동으로 설정해야 합니다. HubConnection 개체의 CookieContainer
속성에 쿠키를 추가합니다. 다음 예제에서는 웹 페이지에서 인증 쿠키를 검색하고 해당 쿠키를 연결에 추가하는 콘솔 앱을 보여 줍니다. 예제의 URL https://www.contoso.com/RemoteLogin
은 만들어야 하는 웹 페이지를 가리킵니다. 페이지에서 게시된 사용자 이름 및 암호를 검색하고 자격 증명을 사용하여 사용자에 로그인하려고 시도합니다.
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();
}
}
연결 헤더
애플리케이션에서 쿠키를 사용하지 않는 경우 연결 헤더에 사용자 정보를 전달할 수 있습니다. 예를 들어 연결 헤더에 토큰을 전달할 수 있습니다.
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();
}
}