.NET Core SignalR: How to accomplish resource-based authorization?










0














All my SignalR clients connect using a JWT bearer token. I utilize the [Authorize] attribute in my SignalR Hub.



This token contains a userId which can be used to check if a user has read access on the resource through the resource's users property which contains a List<PuppyUserPermission> that look like this:



public class PuppyUserPermission

public string userId get; set;
public bool read get; set;
public bool write get; set;



The question is: how do I connect the dots here? Ideally, instead of something like



[Authorize]
public class PuppyHub : Hub

public async Task SendPuppy(Puppy pup)

await Clients.All.SendAsync(pup);




I would so something like the following (this is more pseudo code than anything else, as I don't use valid methods):



[Authorize]
public class PuppyHub : Hub

public async Task SendPuppy(Puppy pup)

var clients = Puppy.users.Where(u => u.read == true);
await clients.SendAsync(pup);




Basically, I'd like to ensure that the clients recieving the Puppy object via SignalR would be authorized users on the resource. Problem is, Clients is just a list of string client IDs, and I'm not sure how to go about tying them to actual users on my Puppy resource.



How do I go about achieving this?










share|improve this question


























    0














    All my SignalR clients connect using a JWT bearer token. I utilize the [Authorize] attribute in my SignalR Hub.



    This token contains a userId which can be used to check if a user has read access on the resource through the resource's users property which contains a List<PuppyUserPermission> that look like this:



    public class PuppyUserPermission

    public string userId get; set;
    public bool read get; set;
    public bool write get; set;



    The question is: how do I connect the dots here? Ideally, instead of something like



    [Authorize]
    public class PuppyHub : Hub

    public async Task SendPuppy(Puppy pup)

    await Clients.All.SendAsync(pup);




    I would so something like the following (this is more pseudo code than anything else, as I don't use valid methods):



    [Authorize]
    public class PuppyHub : Hub

    public async Task SendPuppy(Puppy pup)

    var clients = Puppy.users.Where(u => u.read == true);
    await clients.SendAsync(pup);




    Basically, I'd like to ensure that the clients recieving the Puppy object via SignalR would be authorized users on the resource. Problem is, Clients is just a list of string client IDs, and I'm not sure how to go about tying them to actual users on my Puppy resource.



    How do I go about achieving this?










    share|improve this question
























      0












      0








      0







      All my SignalR clients connect using a JWT bearer token. I utilize the [Authorize] attribute in my SignalR Hub.



      This token contains a userId which can be used to check if a user has read access on the resource through the resource's users property which contains a List<PuppyUserPermission> that look like this:



      public class PuppyUserPermission

      public string userId get; set;
      public bool read get; set;
      public bool write get; set;



      The question is: how do I connect the dots here? Ideally, instead of something like



      [Authorize]
      public class PuppyHub : Hub

      public async Task SendPuppy(Puppy pup)

      await Clients.All.SendAsync(pup);




      I would so something like the following (this is more pseudo code than anything else, as I don't use valid methods):



      [Authorize]
      public class PuppyHub : Hub

      public async Task SendPuppy(Puppy pup)

      var clients = Puppy.users.Where(u => u.read == true);
      await clients.SendAsync(pup);




      Basically, I'd like to ensure that the clients recieving the Puppy object via SignalR would be authorized users on the resource. Problem is, Clients is just a list of string client IDs, and I'm not sure how to go about tying them to actual users on my Puppy resource.



      How do I go about achieving this?










      share|improve this question













      All my SignalR clients connect using a JWT bearer token. I utilize the [Authorize] attribute in my SignalR Hub.



      This token contains a userId which can be used to check if a user has read access on the resource through the resource's users property which contains a List<PuppyUserPermission> that look like this:



      public class PuppyUserPermission

      public string userId get; set;
      public bool read get; set;
      public bool write get; set;



      The question is: how do I connect the dots here? Ideally, instead of something like



      [Authorize]
      public class PuppyHub : Hub

      public async Task SendPuppy(Puppy pup)

      await Clients.All.SendAsync(pup);




      I would so something like the following (this is more pseudo code than anything else, as I don't use valid methods):



      [Authorize]
      public class PuppyHub : Hub

      public async Task SendPuppy(Puppy pup)

      var clients = Puppy.users.Where(u => u.read == true);
      await clients.SendAsync(pup);




      Basically, I'd like to ensure that the clients recieving the Puppy object via SignalR would be authorized users on the resource. Problem is, Clients is just a list of string client IDs, and I'm not sure how to go about tying them to actual users on my Puppy resource.



      How do I go about achieving this?







      .net-core authorization signalr jwt






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 12 '18 at 20:45









      Nickdb93

      196115




      196115






















          1 Answer
          1






          active

          oldest

          votes


















          1














          From the beginning, I had the feeling that the answer lay in IUserIdProvider, but I didn't see how that would work for multiple users.



          I finally found the answer, but it'll definitely need some cleanup.



          First, create your own implementation of IUserIdProvider as follows:



          public class MyUserIdProvider : IUserIdProvider

          public string GetUserId(HubConnectionContext connection)

          var username = connection.User.Claims.Where(x => x.Type == "THE_CLAIM_YOU_WANT_TO_USE_TO_IDENTIFY_USERS").First().Value;
          return username;




          Next, register it using DI:



          services.AddSingleton<IUserIdProvider, MyUserIdProvider >();



          Now, when you want to send events from the server, use DI in your constructor to pull down an instance of your SignalR Hub as per usual:



           private IHubContext<PuppyHub> puppyHub get; 
          public UsersController(IHubContext<PuppyHub> _puppyHub)

          puppyHub = _puppyHub;



          Then, where when you want to tell your clients about the new Puppy:



          // ... typical controller code
          // assume we have a var, puppy, with a list of authorized users

          // use System.Linq to get a list of userIds where the user is authorized to read the puppy
          var authorizedUsers = (IReadOnlyList<string>)puppy.users.Where(x => x.permissions.read == true).Select(i => i._id).ToList();

          // send the new puppy to the authorized users
          await puppyHub.Clients.Users(authorizedUsers).SendAsync("SendPuppy", puppy);


          And viola! You have now done resource-based authorization with SignalR.






          share|improve this answer




















            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53269827%2fnet-core-signalr-how-to-accomplish-resource-based-authorization%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            1














            From the beginning, I had the feeling that the answer lay in IUserIdProvider, but I didn't see how that would work for multiple users.



            I finally found the answer, but it'll definitely need some cleanup.



            First, create your own implementation of IUserIdProvider as follows:



            public class MyUserIdProvider : IUserIdProvider

            public string GetUserId(HubConnectionContext connection)

            var username = connection.User.Claims.Where(x => x.Type == "THE_CLAIM_YOU_WANT_TO_USE_TO_IDENTIFY_USERS").First().Value;
            return username;




            Next, register it using DI:



            services.AddSingleton<IUserIdProvider, MyUserIdProvider >();



            Now, when you want to send events from the server, use DI in your constructor to pull down an instance of your SignalR Hub as per usual:



             private IHubContext<PuppyHub> puppyHub get; 
            public UsersController(IHubContext<PuppyHub> _puppyHub)

            puppyHub = _puppyHub;



            Then, where when you want to tell your clients about the new Puppy:



            // ... typical controller code
            // assume we have a var, puppy, with a list of authorized users

            // use System.Linq to get a list of userIds where the user is authorized to read the puppy
            var authorizedUsers = (IReadOnlyList<string>)puppy.users.Where(x => x.permissions.read == true).Select(i => i._id).ToList();

            // send the new puppy to the authorized users
            await puppyHub.Clients.Users(authorizedUsers).SendAsync("SendPuppy", puppy);


            And viola! You have now done resource-based authorization with SignalR.






            share|improve this answer

























              1














              From the beginning, I had the feeling that the answer lay in IUserIdProvider, but I didn't see how that would work for multiple users.



              I finally found the answer, but it'll definitely need some cleanup.



              First, create your own implementation of IUserIdProvider as follows:



              public class MyUserIdProvider : IUserIdProvider

              public string GetUserId(HubConnectionContext connection)

              var username = connection.User.Claims.Where(x => x.Type == "THE_CLAIM_YOU_WANT_TO_USE_TO_IDENTIFY_USERS").First().Value;
              return username;




              Next, register it using DI:



              services.AddSingleton<IUserIdProvider, MyUserIdProvider >();



              Now, when you want to send events from the server, use DI in your constructor to pull down an instance of your SignalR Hub as per usual:



               private IHubContext<PuppyHub> puppyHub get; 
              public UsersController(IHubContext<PuppyHub> _puppyHub)

              puppyHub = _puppyHub;



              Then, where when you want to tell your clients about the new Puppy:



              // ... typical controller code
              // assume we have a var, puppy, with a list of authorized users

              // use System.Linq to get a list of userIds where the user is authorized to read the puppy
              var authorizedUsers = (IReadOnlyList<string>)puppy.users.Where(x => x.permissions.read == true).Select(i => i._id).ToList();

              // send the new puppy to the authorized users
              await puppyHub.Clients.Users(authorizedUsers).SendAsync("SendPuppy", puppy);


              And viola! You have now done resource-based authorization with SignalR.






              share|improve this answer























                1












                1








                1






                From the beginning, I had the feeling that the answer lay in IUserIdProvider, but I didn't see how that would work for multiple users.



                I finally found the answer, but it'll definitely need some cleanup.



                First, create your own implementation of IUserIdProvider as follows:



                public class MyUserIdProvider : IUserIdProvider

                public string GetUserId(HubConnectionContext connection)

                var username = connection.User.Claims.Where(x => x.Type == "THE_CLAIM_YOU_WANT_TO_USE_TO_IDENTIFY_USERS").First().Value;
                return username;




                Next, register it using DI:



                services.AddSingleton<IUserIdProvider, MyUserIdProvider >();



                Now, when you want to send events from the server, use DI in your constructor to pull down an instance of your SignalR Hub as per usual:



                 private IHubContext<PuppyHub> puppyHub get; 
                public UsersController(IHubContext<PuppyHub> _puppyHub)

                puppyHub = _puppyHub;



                Then, where when you want to tell your clients about the new Puppy:



                // ... typical controller code
                // assume we have a var, puppy, with a list of authorized users

                // use System.Linq to get a list of userIds where the user is authorized to read the puppy
                var authorizedUsers = (IReadOnlyList<string>)puppy.users.Where(x => x.permissions.read == true).Select(i => i._id).ToList();

                // send the new puppy to the authorized users
                await puppyHub.Clients.Users(authorizedUsers).SendAsync("SendPuppy", puppy);


                And viola! You have now done resource-based authorization with SignalR.






                share|improve this answer












                From the beginning, I had the feeling that the answer lay in IUserIdProvider, but I didn't see how that would work for multiple users.



                I finally found the answer, but it'll definitely need some cleanup.



                First, create your own implementation of IUserIdProvider as follows:



                public class MyUserIdProvider : IUserIdProvider

                public string GetUserId(HubConnectionContext connection)

                var username = connection.User.Claims.Where(x => x.Type == "THE_CLAIM_YOU_WANT_TO_USE_TO_IDENTIFY_USERS").First().Value;
                return username;




                Next, register it using DI:



                services.AddSingleton<IUserIdProvider, MyUserIdProvider >();



                Now, when you want to send events from the server, use DI in your constructor to pull down an instance of your SignalR Hub as per usual:



                 private IHubContext<PuppyHub> puppyHub get; 
                public UsersController(IHubContext<PuppyHub> _puppyHub)

                puppyHub = _puppyHub;



                Then, where when you want to tell your clients about the new Puppy:



                // ... typical controller code
                // assume we have a var, puppy, with a list of authorized users

                // use System.Linq to get a list of userIds where the user is authorized to read the puppy
                var authorizedUsers = (IReadOnlyList<string>)puppy.users.Where(x => x.permissions.read == true).Select(i => i._id).ToList();

                // send the new puppy to the authorized users
                await puppyHub.Clients.Users(authorizedUsers).SendAsync("SendPuppy", puppy);


                And viola! You have now done resource-based authorization with SignalR.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 12 '18 at 22:19









                Nickdb93

                196115




                196115



























                    draft saved

                    draft discarded
















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53269827%2fnet-core-signalr-how-to-accomplish-resource-based-authorization%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    這個網誌中的熱門文章

                    How to read a connectionString WITH PROVIDER in .NET Core?

                    Node.js Script on GitHub Pages or Amazon S3

                    Museum of Modern and Contemporary Art of Trento and Rovereto