Implementing Authorization in a Self Hosted SignalR Server accessed from Web

匿名 (未验证) 提交于 2019-12-03 00:48:01

问题:

I'm looking for some guidance on how to implement authorization security for SignalR on a back end service running in a self-hosted (non-IIS) environment, that is called from a Web application. The backend app is basically a monitor that fires SignalR events back to the HTML based client. This all works fine (amazingly well actually).

However, we need to restrict access to the server for authenticated users from the Web site. So basically if a user is authenticated on the Web site, we need to somehow pick up the crendentials (user name is enough) and validation state in the backend app to decide whether to allow the connection as to avoid unauthorized access.

Can anybody point at some strategies or patterns on how to accomplish this sort of auth forwarding?

回答1:

SignalR does not provide any additional features for authentication. Instead, it is designed to work with the authentication mechanism of your application.

Hubs

You should do authentication as you normally would and then use the Authorize attribute provided by SignalR to enforce the results of the authentication on the Hubs.

The Authorize attribute can be applied to an entire Hub or particular methods in the Hub. Some examples:

You can also require all Hubs to require authentication by adding the following method in the Application_Start method:

GlobalHost.HubPipeline.RequireAuthentication();

Persistent Connections

You can use the user object in the request to see if the user is authenticated:

request.User.IsAuthenticated



回答2:

I am having similar issues here, as in my web app I use a simple cookie authentication system which uses an AoP style approach to check for any controllers with an attribute, then will get the current context (be it from the static HttpContext.Current or from the target invocation object depending on the type of interceptor) and then verify the cookie exists, it contains right data, then finally verify the token with the db or cache etc.

Anyway this approach can also be used for Signalr, although its a bit more long winded and you are using dependency injection. You would basically wrap the hub calls with the desired attribute, then set up your DI/IoC configuration to intercept these calls, then either get the hub instance within your interceptor and get the cookie (or your custom authentication mechanism) from the request, verify it is all valid or not, and if not then throw a new HttpException("403", "Not authenticated"); which should kick the user out and return back before it even hits your hub method, this way you can put the logic in one place (your interceptor, or a class the interceptor consumes) then just wrap any method that needs to use this authentication using your attribute.

I use Ninject and the interception extension, but most major DI frameworks these days have some form of IoC plugin/extensions, such as Autofac, Windsor, Spring etc.

If you were not happy going down the route of introducing DI and/or AOP to your current project, then maybe you could just create a custom hub instance which contains your authentication logic and then just use that in your hubs, so ok you will still be manually calling some authentication logic from within each hub method you want to protect, but its less code, so something like:

public class AuthorisableHub : Hub {     private ISomeAuthenticationToken GetSomeAuthenticationTokenFromRequest(Request request) // probably a SignalR specific request object     {         // Get your token from the querystring or cookie etc     }      private bool IsAuthenticationTokenValid(ISomeAuthenticationToken token)     {         // Perform some validation, be it simple or db based and return result     }      protected void PerformUserAuthentication()     {         var token = GetSomeAuthenticationTokenFromRequest(Context.Request);         var isRequestValid = IsAuthenticationTokenValid(token);          if(!isRequestValid)         { throw new HttpException(403, "<Some forbidden message here>"); }     } }  public class MyFancyPantsHub : AuthorisableHub {     public void TellAllClientsSomethingSecret(ISecret secret)     {         PerformUserAuthentication();          // Do stuff with the secret as it should have bombed the user out         // before it reaches here if working correctly     } } 

It is not perfect but would work (I think), also I am sure I once read somewhere that Hubs are newly instantiated for each request, and if this is indeed true, you could possibly just put this logic in your constructor if you want to apply the authentication to every action within the hub.

Hope that helps, or gives you ideas... would be interested in knowing how you did solve it in the end.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!