Skip to content

Latest commit

 

History

History
406 lines (309 loc) · 17.3 KB

functions-bindings-signalr-service-input.md

File metadata and controls

406 lines (309 loc) · 17.3 KB
title description author ms.topic ms.devlang ms.custom ms.date ms.author zone_pivot_groups
Azure Functions SignalR Service input binding
Learn to return a SignalR service endpoint URL and access token in Azure Functions.
Y-Sindo
reference
csharp
devx-track-csharp, devx-track-extended-java, devx-track-js, devx-track-python
12/29/2024
zityang
programming-languages-set-functions-lang-workers

SignalR Service input binding for Azure Functions

Before a client can connect to Azure SignalR Service, it must retrieve the service endpoint URL and a valid access token. The SignalRConnectionInfo input binding produces the SignalR Service endpoint URL and a valid token that are used to connect to the service. The token is time-limited and can be used to authenticate a specific user to a connection. Therefore, you shouldn't cache the token or share it between clients. Usually you use SignalRConnectionInfo with HTTP trigger for clients to retrieve the connection information.

For more information on how to use this binding to create a "negotiate" function that is compatible with a SignalR client SDK, see Azure Functions development and configuration with Azure SignalR Service.

When not explicitly declared, assume that examples are using the default connection setting value of AzureSignalRConnectionString. For information on setup and configuration details, see the overview.

Example

::: zone pivot="programming-language-csharp"

[!INCLUDE functions-bindings-csharp-intro-with-csx]

[!INCLUDE functions-in-process-model-retirement-note]

The following example shows a C# function that acquires SignalR connection information using the input binding and returns it over HTTP.

:::code language="csharp" source="~/azure-functions-dotnet-worker/samples/Extensions/SignalR/SignalRNegotiationFunctions.cs" id="snippet_negotiate":::

The following example shows a C# function that acquires SignalR connection information using the input binding and returns it over HTTP.

[FunctionName("negotiate")]
public static SignalRConnectionInfo Negotiate(
    [HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest req,
    [SignalRConnectionInfo(HubName = "hubName1")]SignalRConnectionInfo connectionInfo)
{
    return connectionInfo;
}

::: zone-end

::: zone pivot="programming-language-python,programming-language-powershell"

[!INCLUDE functions-bindings-signalr-input-function-json]

::: zone-end ::: zone pivot="programming-language-javascript"

Here's the JavaScript code:

const { app, input } = require('@azure/functions');

const inputSignalR = input.generic({
    type: 'signalRConnectionInfo',
    name: 'connectionInfo',
    hubName: 'hubName1',
    connectionStringSetting: 'AzureSignalRConnectionString',
});

app.post('negotiate', {
    authLevel: 'function',
    handler: (request, context) => {
        return { body: JSON.stringify(context.extraInputs.get(inputSignalR)) }
    },
    route: 'negotiate',
    extraInputs: [inputSignalR],
});

[!INCLUDE functions-bindings-signalr-input-function-json]

module.exports = async function (context, req, connectionInfo) {
    context.res.body = connectionInfo;
};

::: zone-end ::: zone pivot="programming-language-powershell"

Complete PowerShell examples are pending. ::: zone-end ::: zone pivot="programming-language-python"

The following example shows a SignalR connection info input binding in a function.json file and a Python function that uses the binding to return the connection information.

Here's the Python code:

def main(req: func.HttpRequest, connectionInfoJson: str) -> func.HttpResponse:
    return func.HttpResponse(
        connectionInfoJson,
        status_code=200,
        headers={
            'Content-type': 'application/json'
        }
    )

::: zone-end ::: zone pivot="programming-language-java"

The following example shows a Java function that acquires SignalR connection information using the input binding and returns it over HTTP.

@FunctionName("negotiate")
public SignalRConnectionInfo negotiate(
        @HttpTrigger(
            name = "req",
            methods = { HttpMethod.POST },
            authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> req,
        @SignalRConnectionInfoInput(
            name = "connectionInfo",
            HubName = "hubName1") SignalRConnectionInfo connectionInfo) {
    return connectionInfo;
}

:::zone-end ::: zone pivot="programming-language-csharp"

Attributes

Both in-process and isolated worker process C# libraries use attribute to define the function. C# script instead uses a function.json configuration file.

The following table explains the properties of the SignalRConnectionInfoInput attribute:

Attribute property Description
HubName Required. The hub name.
ConnectionStringSetting The name of the app setting or settings collection that contains the SignalR Service connection string, which defaults to AzureSignalRConnectionString.
UserId Optional. The user identifier of a SignalR connection. You can use a binding expression to bind the value to an HTTP request header or query.
IdToken Optional. A JWT whose claims will be added to the user claims. It should be used together with ClaimTypeList. You can use a binding expression to bind the value to an HTTP request header or query.
ClaimTypeList Optional. A list of claim types, which filter the claims in IdToken .

The following table explains the properties of the SignalRConnectionInfo attribute:

Attribute property Description
HubName Required. The hub name.
ConnectionStringSetting The name of the app setting or settings collection that contains the SignalR Service connection string, which defaults to AzureSignalRConnectionString.
UserId Optional. The user identifier of a SignalR connection. You can use a binding expression to bind the value to an HTTP request header or query.
IdToken Optional. A JWT whose claims will be added to the user claims. It should be used together with ClaimTypeList. You can use a binding expression to bind the value to an HTTP request header or query.
ClaimTypeList Optional. A list of claim types, which filter the claims in IdToken .

::: zone-end ::: zone pivot="programming-language-java"

Annotations

The following table explains the supported settings for the SignalRConnectionInfoInput annotation.

Setting Description
name Variable name used in function code for connection info object.
hubName Required. The hub name.
connectionStringSetting The name of the app setting or settings collection that contains the SignalR Service connection string, which defaults to AzureSignalRConnectionString.
userId Optional. The user identifier of a SignalR connection. You can use a binding expression to bind the value to an HTTP request header or query.
idToken Optional. A JWT whose claims will be added to the user claims. It should be used together with claimTypeList. You can use a binding expression to bind the value to an HTTP request header or query.
claimTypeList Optional. A list of claim types, which filter the claims in idToken .

::: zone-end

::: zone pivot="programming-language-javascript"

Annotations

The following table explains the supported settings for the SignalRConnectionInfoInput annotation.

Setting Description
name Variable name used in function code for connection info object.
hubName Required. The hub name.
connectionStringSetting The name of the app setting or settings collection that contains the SignalR Service connection string, which defaults to AzureSignalRConnectionString.
userId Optional. The user identifier of a SignalR connection. You can use a binding expression to bind the value to an HTTP request header or query.
idToken Optional. A JWT whose claims will be added to the user claims. It should be used together with claimTypeList. You can use a binding expression to bind the value to an HTTP request header or query.
claimTypeList Optional. A list of claim types, which filter the claims in idToken .

::: zone-end

::: zone pivot="programming-language-powershell,programming-language-python"

Configuration

The following table explains the binding configuration properties that you set in the function.json file.

function.json property Description
type Must be set to signalRConnectionInfo.
direction Must be set to in.
hubName Required. The hub name.
connectionStringSetting The name of the app setting or settings collection that contains the SignalR Service connection string, which defaults to AzureSignalRConnectionString.
userId Optional. The user identifier of a SignalR connection. You can use a binding expression to bind the value to an HTTP request header or query.
idToken Optional. A JWT whose claims will be added to the user claims. It should be used together with claimTypeList. You can use a binding expression to bind the value to an HTTP request header or query.
claimTypeList Optional. A list of claim types, which filter the claims in idToken .

::: zone-end

Warning

For the simplicity, we omit the authentication and authorization parts in this sample. As a result, this endpoint is publicly accessible without any restrictions. To ensure the security of your negotiation endpoint, you should implement appropriate authentication and authorization mechanisms based on your specific requirements. For guidance on protecting your HTTP endpoints, see the following articles:

Usage

Managed identity-based connections

[!INCLUDE functions-azure-signalr-authorization-note]

Authenticated tokens

When an authenticated client triggers the function, you can add a user ID claim to the generated token. You can easily add authentication to a function app using App Service Authentication.

App Service authentication sets HTTP headers named x-ms-client-principal-id and x-ms-client-principal-name that contain the authenticated user's client principal ID and name, respectively.

You can set the UserId property of the binding to the value from either header using a binding expression: {headers.x-ms-client-principal-id} or {headers.x-ms-client-principal-name}.

::: zone pivot="programming-language-csharp"

[Function("Negotiate")]
public static string Negotiate([HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequestData req,
    [SignalRConnectionInfoInput(HubName = "hubName1", UserId = "{headers.x-ms-client-principal-id}")] string connectionInfo)
{
    // The serialization of the connection info object is done by the framework. It should be camel case. The SignalR client respects the camel case response only.
    return connectionInfo;
}
[FunctionName("negotiate")]
public static SignalRConnectionInfo Negotiate(
    [HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest req,
    [SignalRConnectionInfo
        (HubName = "hubName1", UserId = "{headers.x-ms-client-principal-id}")]
        SignalRConnectionInfo connectionInfo)
{
    // connectionInfo contains an access key token with a name identifier claim set to the authenticated user
    return connectionInfo;
}

::: zone-end

::: zone pivot="programming-language-java"

@FunctionName("negotiate")
public SignalRConnectionInfo negotiate(
        @HttpTrigger(
            name = "req",
            methods = { HttpMethod.POST, HttpMethod.GET },
            authLevel = AuthorizationLevel.ANONYMOUS)
            HttpRequestMessage<Optional<String>> req,
        @SignalRConnectionInfoInput(name = "connectionInfo", hubName = "hubName1", userId = "{headers.x-ms-signalr-userid}") SignalRConnectionInfo connectionInfo) {
    return connectionInfo;
}

::: zone-end

::: zone pivot="programming-language-python,programming-language-powershell"

Here's binding data in the function.json file:

{
    "type": "signalRConnectionInfo",
    "name": "connectionInfo",
    "hubName": "hubName1",
    "userId": "{headers.x-ms-client-principal-id}",
    "connectionStringSetting": "<name of setting containing SignalR Service connection string>",
    "direction": "in"
}

::: zone-end ::: zone pivot="programming-language-javascript" Here's the JavaScript code:

const { app, input } = require('@azure/functions');

const inputSignalR = input.generic({
    type: 'signalRConnectionInfo',
    name: 'connectionInfo',
    hubName: 'hubName1',
    connectionStringSetting: 'AzureSignalRConnectionString',
    userId: '{headers.x-ms-client-principal-id}',
});

app.post('negotiate', {
    authLevel: 'function',
    handler: (request, context) => {
        return { body: JSON.stringify(context.extraInputs.get(inputSignalR)) }
    },
    route: 'negotiate',
    extraInputs: [inputSignalR],
});

Here's binding data in the function.json file:

{
    "type": "signalRConnectionInfo",
    "name": "connectionInfo",
    "hubName": "hubName1",
    "userId": "{headers.x-ms-client-principal-id}",
    "connectionStringSetting": "<name of setting containing SignalR Service connection string>",
    "direction": "in"
}
module.exports = async function (context, req, connectionInfo) {
    // connectionInfo contains an access key token with a name identifier
    // claim set to the authenticated user
    context.res.body = connectionInfo;
};

::: zone-end ::: zone pivot="programming-language-powershell"

Complete PowerShell examples are pending. ::: zone-end ::: zone pivot="programming-language-python"

Here's the Python code:

def main(req: func.HttpRequest, connectionInfo: str) -> func.HttpResponse:
    # connectionInfo contains an access key token with a name identifier
    # claim set to the authenticated user
    return func.HttpResponse(
        connectionInfo,
        status_code=200,
        headers={
            'Content-type': 'application/json'
        }
    )

::: zone-end ::: zone pivot="programming-language-java"

@FunctionName("negotiate")
public SignalRConnectionInfo negotiate(
        @HttpTrigger(
            name = "req",
            methods = { HttpMethod.POST },
            authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> req,
        @SignalRConnectionInfoInput(
            name = "connectionInfo",
            HubName = "hubName1",
            userId = "{headers.x-ms-client-principal-id}") SignalRConnectionInfo connectionInfo) {
    return connectionInfo;
}

::: zone-end

Binding expressions for HTTP trigger

It's a common scenario that the values of some attributes of SignalR input binding come from HTTP requests. Therefore, we show how to bind values from HTTP requests to SignalR input binding attributes via binding expression.

HTTP metadata type Binding expression format Description Example
HTTP request query {query.QUERY_PARAMETER_NAME} Binds the value of corresponding query parameter to an attribute {query.userName}
HTTP request header {headers.HEADER_NAME} Binds the value of a header to an attribute {headers.token}

Next steps