Azure Functions with SignalR: Unauthorized when trying to get access to SignalR Service - azure

i am currently developing a real time analytic Dashboard with Stream Analytics -> Azure Functions -> SignalRService -> Angular Web App.
I am struggling when i want to authorize my function with the signalr service. Therefore i added the Connectionstring to my Appsettings. When i try to send a SignalRMessage, it says that i am unauthroized. Isnt it just setting the Connectionstring with the Accesskey in AppSettings of the Function?
Current Error:
Microsoft.Azure.SignalR.Common.AzureSignalRUnauthorizedException: 'Authorization failed. If you were using AccessKey, please check connection string and see if the AccessKey is correct. If you were using Azure Active Directory, please note that the role assignments will take up to 30 minutes to take effect if it was added recently. Request Uri: https://signalrtest2.service.signalr.net/api/v1/hubs/pa'
FunctionCode:
[FunctionName("CreateRealTimeAnalytics")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
[SignalR(HubName = "pa")] IAsyncCollector<SignalRMessage> signalRMessages)
{
// Extract the body from the request
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
if (string.IsNullOrEmpty(requestBody)) { return new StatusCodeResult(204); } // 204, ASA connectivity check
var data = JsonConvert.DeserializeObject<StreamUsageHeartbeatAnalytics>(requestBody);
var dataString = Newtonsoft.Json.JsonConvert.SerializeObject(data);
await signalRMessages.AddAsync(
new SignalRMessage
{
Target = "pa",
Arguments = new[] { dataString }
});
return new OkResult(); // 200
}
[FunctionName("Negotiate")]
public static SignalRConnectionInfo Negotiate(
[HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req,
[SignalRConnectionInfo(HubName = "pa")] SignalRConnectionInfo connectionInfo)
{
return connectionInfo;
}

To achieve the above requirement we have tried to add the below connection string format which is working fine So please make sure that you have provided proper Connection string with below format in your Appsettings.
Azure__SignalR__ConnectionString : Value(My connection string)
For more information please refer the below Links:-
MICROSOFT DOCUMENTATION - Azure Function SignalIR Bindings
SO THREAD:- Unable to read Azure SignalR Connection String from Azure App Service Configuration Application Settings

Related

REST Api is not returning expected data

I wrote an Auth API where it should retrieve the details from my user, but I'm getting error 404 instead. All my users are stored in an Azure Storage Account, and I was using the TableClient class to handle with my table. However I am not able to go any further when I started to do this Auth. I spent over one week only on this function, and I got no progress on this, here is my code:
[FunctionName(nameof(Auth))]
public static async Task<IActionResult> Auth(
[HttpTrigger(AuthorizationLevel.Admin, "POST", Route = "auth")] HttpRequest req,
[Table("User", Connection = "AzureWebJobsStorage")] TableClient tdClient,
ILogger log)
{
string url = String.Format("http://localhost:7235/api/");
HttpMessageHandler handler = new HttpClientHandler()
{
};
var httpClient = new HttpClient(handler)
{
BaseAddress = new Uri(url),
Timeout = new TimeSpan(0, 2, 0)
};
httpClient.DefaultRequestHeaders.Add("ContentType", "application/json");
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes("roy.mitchel#somecompany.com:pass1234");
string val = System.Convert.ToBase64String(plainTextBytes);
httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + val);
HttpResponseMessage response = httpClient.GetAsync(url).Result;
return new OkObjectResult(response);
}
How can auth my user using this class? Iam doing on the right way?
Thanks.
Debugging any API issues by looking at just the code, is (as you have discovered) a horribly painful process.
I'd strongly recommend using a MITM proxy (like burp) to get visibility of exactly what is sent to, and received from the API. By using this approach, it generally becomes really obvious what is wrong.
If you can't use this approach, then enable logging for the raw HTTP request and response, as outlined in this guide.

Azure Functions isolated .Net 6.0 + SignalR

My goal is to:
In scheduled functions - add message to SignalR
In SPA application (vue.js) subscribe to the event and call API to update the view
For now I'm trying to get anything to/from SignalR in my Function app (isolated, .net 6.0).
What I have in a function app:
[Function("negotiate")]
public HttpResponseData Negotiate(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req,
[SignalRConnectionInfoInput(HubName = "AdminHub", ConnectionStringSetting = "AzureSignalRConnectionString")] SignalRConnectionInfo connectionInfo)
{
_logger.LogInformation($"SignalR Connection URL = '{connectionInfo.Url}'");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString($"Connection URL = '{connectionInfo.Url}'");
return response;
}
}
[Function("SendMessage")]
[SignalROutput(HubName = "AdminHub", ConnectionStringSetting = "AzureSignalRConnectionString")]
public SignalRMessage SendMessage(
[HttpTrigger(AuthorizationLevel.Anonymous, "get")] Microsoft.Azure.Functions.Worker.Http.HttpRequestData req)
{
return
new SignalRMessage
{
Target = "cancelToHandle",
MethodName = "cancelToHandle",
Arguments = new[] { "hello" }
};
}
[Function("SignalRTest")]
public static async Task SignalRTest([SignalRTrigger("AdminHub", "messages", "cancelToHandle", ConnectionStringSetting = "AzureSignalRConnectionString")] string message, ILogger logger)
{
logger.LogInformation($"Receive {message}.");
}
Negotiate function is not called. When should it be called?
If I call SendMessage, no error, but nothing happens in SignalR service. Should I see connections and messages there? (zero in the Metrics for now).
I've tried to create a test "emulator" client - just a console application:
var url = "http://<azureSignalRUrl>/AdminHub";
var connection = new HubConnectionBuilder()
.WithUrl(url)
.WithAutomaticReconnect()
.Build();
// receive a message from the hub
connection.On<string, string>("cancelToHandle", (user, message) => OnReceiveMessage(user, message));
await connection.StartAsync();
// send a message to the hub
await connection.InvokeAsync("SendMessage", "ConsoleApp", "Message from the console app");
void OnReceiveMessage(string user, string message)
{
Console.WriteLine($"{user}: {message}");
}
and it throws the exception ": 'A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. (:80)'
I think I'm missing overall understanding of what is supposed to happen:
when should negotiate function be triggered
can I see messages that I send in Azure portal (in SignalR service)?
how can I easily receive them in testing purposes
what do parameters/properties mean (target / method name / category). Example:
SignalRTriggerAttribute has the following constructor
public SignalRTriggerAttribute(string hubName, string category, string #event, params string[] parameterNames);
and Output binding receives any custom model I create?
which settings should be set in SignalR service - for now all I set it Serverless mode + CORS
Here are the few link which will help in using SignalIr service extension in functions
Using SignalIr service extension
https://github.com/Azure/azure-functions-dotnet-worker/blob/main/samples/Extensions/SignalR/SignalRFunction.cs
Below is the sample link for triggering negotiate function
https://github.com/Log234/azure-functions-signalr-dotnet-isolated-demo/blob/main/SignalRDemo/NegotiationFunctions.cs
for complete understanding of SignalIR here is the Github and MS document.

Http Trigger Azure function should not accessible outside from App Service

I am using http trigger azure function in my App Service. I want this http trigger azure function should not accessible publicly and accessible only from the App Service.
Currently I have created host key for http trigger function and I am using this for authenticate request.
Which authentication method should I use for this? Any thoughts.
Azure Function:
public static class RemoveSubscriptionsForPayers
{
[FunctionName(nameof(RemoveSubscriptionsForPayers))]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
[Inject] ILoggingService loggingService,
[Inject] ICommandValidator commandValidator,
[Inject] ICommandHandler<ResultDto,RemoveSubscriptionsForPayersCommand> commandHandler)
{
var logger = new Logger(loggingService);
try
{
IActionResult actionResult = null;
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
logger.Info($"RemoveSubscriptionsForPayersCommand received on {nameof(RemoveSubscriptionsForPayers)}");
var command = requestBody.AsPoco<RemoveSubscriptionsForPayersCommand>();
if (commandValidator.Validate<RemoveSubscriptionsForPayersCommand>(req, command, new RemoveSubscriptionsForPayersCommandValidator(), logger, ref actionResult))
{
var response =await commandHandler.HandleAsync(command, logger);
actionResult = new OkObjectResult(response);
}
return actionResult;
}
catch (Exception ex)
{
logger.Error($"Exception while processing {nameof(RemoveSubscriptionsForPayers)}", ex,
nameof(RemoveSubscriptionsForPayers));
throw;
}
}
}
You can use Azure AD to authenticate your functions, which is more secure.
After opening Azure AD authentication, you need to obtain an access token.
Please open Azure active directory in the Azure portal and find App registrations, you need to search for the function you registered in Azure AD in the search box.
you need to find the parameter values of the url and body to obtain the token here.
URL to get access token
Body:
client_id
scope
username and password
grant_type: The value of grant_type is fixed, both are password.
client_secret
You can get Token like this:
Now you can use the access token of Azure AD to access your functions.
The request header name is Authorization, and the header value is Bearer <access-token>:

Azure Function App documentation using API Management

I have created a Azure Function App. The function app connects to a SQL DB and has the following features
Return all the records in a table
Returns the records based on the column name using the below code
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
string loan_id = req.Query["loanid"];
string loan_amount = req.Query["loanamount"];
if (string.IsNullOrEmpty(loan_id)) {
//Do something when dont give loan id.
} else if (string.IsNullOrEmpty(loan_amount)) {
//DO something when dont give loan amount.
}
return new OkObjectResult("This is a test.");
}
I would like to document the function app using API Management/Swagger. Can you please let me know how this can be achieved?
Thanks in advance
You just need to create an API management service instance from the portal and add the function endpoint using the open api.
You can follow this documentation on how to do the same.

HTTPTrigger Azure Function with CosmosDb input is not working after deployment

I have created below HttpTrigger function which takes CosmosDb item as input. This code works perfectly fine on when run locally. I am using Visual Studio Code to create function and deploying to Azure after successfully ran locally. But it doesn't work on Azure, it doesn't give error or it seems it not getting any response.
public static class HttpTriggerWithCosmosDb
{
[FunctionName("HttpTriggerWithCosmosDb")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "HttpTriggerWithCosmosDb/{id}")] HttpRequest req,
[CosmosDB(
databaseName : "func-io-learn-db",
collectionName : "Bookmarks",
ConnectionStringSetting = "CosmosDBConnection",
Id = "{id}",
PartitionKey = "{id}"
)] BookMarkItem item,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = item.Url;
Console.Write( item.Id);
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
string responseMessage = string.IsNullOrEmpty(name)
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
: $"Hello, {name}. This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
}
}
While publishing, in output I see below message:
HttpTriggerCSharp1:
https://nps-func.azurewebsites.net/api/HttpTriggerCSharp1
TestMessage: https://nps-func.azurewebsites.net/api/TestMessage
5:33:02 PM nps-func: WARNING: Some http trigger urls cannot be
displayed in the output window because they require an authentication
token.
It is not showing This above function in response.
Update:
Full code can be found on Git
I got the issue, what is happening here. I had to manually add CosmosDBConnection to Azure with Azure Function:Add New Settings... command before I publish the function.
I am new to function, I was not aware this is how app_settings need to be added.

Resources