ASP.NET SignalR 1.0 では MVC や Web API のように属性を使った認証に対応しました。以前から要求が多かったのに対応が遅くなったのには、SignalR に特有の事情がありました。
そして今回、実際に実装された Authorize 属性を見ると Role や User といった MVC 互換のプロパティの他に Mode という AuthorizeMode 型のプロパティが追加されています。AuthorizeMode 型には Incoming/Outgoing/Both の 3 つの値が定義されていて、それぞれ挙動が異なりますので調査しました。
今回サンプルとして使用する、基本となる Hub の実装です。
[Authorize] [HubName("auth")] public class AuthHub : Hub { public string Incoming() { return "OK"; } public void Outgoing() { Clients.All.Receive("OK"); } }
Incoming メソッドは単純に値を返すだけ、Outgoing メソッドは全てのクライアントへプッシュを行います。それでは、AuthorizeMode の値を変更して確認していきます。
そして実際にハブのメソッドを呼び出す JavaScript は以下のようになります。
$(function() { var connection = $.hubConnection(); var auth = connection.createHubProxy("auth"); auth.on("Receive", function (result) { alert(result); }); connection.start(function() { //auth.invoke("Incoming"); //auth.invoke("Outgoing"); }); });
実際のメソッド呼び出しはコメントを削除して Incoming と Outgoing の時でそれぞれ切り替えて試すようにします。
AuthorizeMode.Incoming
クライアントからサーバへの通信に対して認証を要求する。
[Authorize(Mode = AuthorizeMode.Incoming)] [HubName("auth")] public class AuthHub : Hub { public string Incoming() { return "OK"; } public void Outgoing() { Clients.All.Receive("OK"); } }
Incoming はクライアントからのリクエストに対して認証を要求します。ですので、実際の挙動は MVC や Web API の Authorize 属性に非常に似ています。
つまりログインしていない状態では invoke メソッドの呼び出しはブロックされますが、on メソッドで定義した関数は呼び出されます。
AuthorizeMode.Outgoing
サーバからクライアントへの通信に対して認証を要求する。
[Authorize(Mode = AuthorizeMode.Outgoing)] [HubName("auth")] public class AuthHub : Hub { public string Incoming() { return "OK"; } public void Outgoing() { Clients.All.Receive("OK"); } }
Outgoing の挙動は Incoming と比べて、ちょっと理解しにくい感じです。サーバからクライアントへの通信に対して認証を要求するので、別のクライアントによるブロードキャスト要求もブロックされることになります。
つまり on メソッドで定義した関数はブロックされますが、invoke メソッドでの呼び出しは成功します。
AuthorizeMode.Both
[Authorize(Mode = AuthorizeMode.Both)] [HubName("auth")] public class AuthHub : Hub { public string Incoming() { return "OK"; } public void Outgoing() { Clients.All.Receive("OK"); } }
Both はその名の通り Incoming と Outgoing を組み合わせたものなので、MVC や Web API の Authorize とほぼ同じです。Authorize 属性のデフォルトは Both なので、AuthorizeMode を指定しない使い方が一般的かと思います。