duta
duta

Reputation: 63

Authentication in ASP.NET Core Web API and Azure SignalR service

I have an ASP.NET Core Web API wherein I host a SignalR hub.

I have created an Azure SignalR service, which the SignalR hub connects to at startup, using the connection string provided when I created the Azure SignalR service.

I have a winforms client app that connects to the SignalR hub at startup. The users of the Winforms app is authenticated using IWA.

I have the Web API only to host the SignalR Hub, so I will NOT be adding/using controllers in my Web API. But add functionality to support the Winforms client app.

So my question is since it's hosted in Azure, I need to secure the API from unauthorized access. If I understand it correctly this can be achieved by adding the [Authorize] on the controller that came with the project template?

Or can I simply delete the controller and that way no one from outside can access the API?

And do I need to somehow secure my SignalR Hubs from unauthorized access as well?

Upvotes: 1

Views: 799

Answers (2)

Jason Pan
Jason Pan

Reputation: 22082

can I simply delete the controller and that way no one from outside can access the API? Answer: Yes

do I need to somehow secure my SignalR Hubs from unauthorized access as well? Answer: You also can add IWA in your web pplication.


I create a brand new asp.net core mvc project(I know you are using webapi), it's easy for me to test in webpage.

Thanks for Harshitha's test result, we can delete all the controllers, it also could work fine.

And I have enable windows authentication in project. Like :

 builder.Services.AddAuthentication(IISDefaults.AuthenticationScheme)

.AddNegotiate();

We need to add [Authorize] for our hub class.

enter image description here

Then I create a winform application, here is my code:

Form1.Designer.cs

namespace WinFormsApp1
{
    partial class Form1
    {
        /// <summary>
        ///  Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        ///  Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        ///  Required method for Designer support - do not modify
        ///  the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            button1 = new Button();
            button2 = new Button();
            richTextBox1 = new RichTextBox();
            SuspendLayout();
            // 
            // button1
            // 
            button1.Location = new Point(38, 28);
            button1.Name = "button1";
            button1.Size = new Size(156, 23);
            button1.TabIndex = 1;
            button1.Text = "without IWA log-in";
            button1.UseVisualStyleBackColor = true;
            button1.Click += button1_Click;
            // 
            // button2
            // 
            button2.Location = new Point(38, 75);
            button2.Name = "button2";
            button2.Size = new Size(156, 23);
            button2.TabIndex = 2;
            button2.Text = "IWA connect to signalr";
            button2.UseVisualStyleBackColor = true;
            button2.Click += button2_Click;
            // 
            // richTextBox1
            // 
            richTextBox1.Location = new Point(38, 127);
            richTextBox1.Name = "richTextBox1";
            richTextBox1.Size = new Size(694, 280);
            richTextBox1.TabIndex = 3;
            richTextBox1.Text = "";
            // 
            // Form1
            // 
            AutoScaleDimensions = new SizeF(7F, 15F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(800, 450);
            Controls.Add(richTextBox1);
            Controls.Add(button2);
            Controls.Add(button1);
            Name = "Form1";
            Text = "Form1";
            Load += Form1_Load;
            ResumeLayout(false);
        }

        #endregion
        private Button button1;
        private Button button2;
        private RichTextBox richTextBox1;
    }
}

Form1.cs

using Microsoft.AspNetCore.SignalR.Client;
using System.Data.Common;

namespace WinFormsApp1
{
    public partial class Form1 : Form
    {
        HubConnection _connection;
        public Form1()
        {
            InitializeComponent();
            _connection = new HubConnectionBuilder().WithUrl($"https://localhost:44356/mainHub")
                .WithAutomaticReconnect()
                .Build();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            _connection = new HubConnectionBuilder().WithUrl("https://localhost:44376/mainhub").Build();
            try
            {
                _connection.StartAsync();

                for (int i = 0; i < 10; i++)
                {
                    richTextBox1.AppendText("without IWA log-in   " +DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "   " + _connection.State.ToString() + "\r\n");
                    if (_connection.State.ToString() == "Connected" || _connection.State.ToString() == "Disconnected") {
                        return;
                    }
                    Thread.Sleep(1000);
                }
                
            }
            catch (Exception ex)
            {
                richTextBox1.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "   " + ex.ToString() + "\r\n");
                throw;
            }
            
        }

        private void button2_Click(object sender, EventArgs e)
        {
            _connection = new HubConnectionBuilder().WithUrl("https://localhost:44376/mainhub", options =>
            {
                options.UseDefaultCredentials = true;
            }).Build();
            _connection.StartAsync();
            for (int i = 0; i < 10; i++)
            {
                richTextBox1.AppendText("IWA connect to signalr   " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "   " + _connection.State.ToString() + "\r\n");
                if (_connection.State.ToString() == "Connected")
                {
                    return;
                }
                Thread.Sleep(1000);
            }

        }

    }
}

And the test result.

enter image description here

The most important things

is we should use this package `Microsoft.AspNetCore.SignalR.Client` and create Winform application based on .net core, not .net framework.

Upvotes: 0

Harshitha
Harshitha

Reputation: 7367

If I understand it correctly this can be achieved by adding the [Authorize] on the controller that came with the project template?

Yes, to secure and authenticate a Controller / Web API Action method [Authorize] attribute has to be added.

When we select Authentication type while Creating a WebApp,

enter image description here

By default, Controller Action methods will be decorated with [Authorize] attribute.

Auto Generated Code in Controller:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web.Resource;

namespace SignalR.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    [RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "---------"
    };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }     
    }
}
  • Members who are successfully authenticated will only be able to access the above Action Method.

can I simply delete the controller and that way no one from outside can access the API?

  • As you have already added the [Authorize] attribute the method can be accessed only by the authenticated users.

  • AFAIK, no need to delete the controller. If you delete the controller action method, then you need to access the Azure SignalR services directly.

  • I have tried to run the App by deleting the controller, I haven't faced any issues.

enter image description here

enter image description here

  • In that case we need to add [Authorize] tag to the Azure Signal R method as mentioned in this Article.

do I need to somehow secure my SignalR Hubs from unauthorized access as well?

Yes, we can add [Authorize] attribute for a SignalR service as well.

Refer Various Ways to Authenticate and Authorize SignalR Hubs for more details.

Upvotes: 0

Related Questions