When Azure SignalR Service is used with Functions, negotiating the protocol starts by getting the first connection information from Functions that contains both an access token and an url to redirect. The client will use these to connect to the SignalR Service.
Azure SignalR Service with Azure Functions Authorization¶
To send x-ms-client-principal-id header for PlayFab and x-functions-key for Azure Functions key the default authenticator can be modified to append these headers in PrepareRequest:
usingSystem;usingBest.SignalR;namespaceBest.SignalR.Authentication{publicsealedclassAccessTokenAuthenticatorWithAuzreFunctionAuthorization:IAuthenticationProvider{/// <summary>/// No pre-auth step required for this type of authentication/// </summary>publicboolIsPreAuthRequired{get{returnfalse;}}#pragma warning disable 0067/// <summary>/// Not used event as IsPreAuthRequired is false/// </summary>publiceventOnAuthenticationSuccededDelegateOnAuthenticationSucceded;/// <summary>/// Not used event as IsPreAuthRequired is false/// </summary>publiceventOnAuthenticationFailedDelegateOnAuthenticationFailed;#pragma warning restore 0067privateHubConnection_connection;privatestring_playFabId;privatestring_clientPrincipalId;publicAccessTokenAuthenticatorWithAuzreFunctionAuthorization(HubConnectionconnection,stringplayFabId,stringclientPrincipalId){this._connection=connection;this._playFabId=playFabId;this._clientPrincipalId=clientPrincipalId;}/// <summary>/// Not used as IsPreAuthRequired is false/// </summary>publicvoidStartAuthentication(){}/// <summary>/// Prepares the request by adding two headers to it/// </summary>publicvoidPrepareRequest(Best.HTTP.HTTPRequestrequest){// Add Authorization header to http requests, add access_token param to the uri otherwiseif(Best.HTTP.Hosts.Connections.HTTPProtocolFactory.GetProtocolFromUri(request.CurrentUri)==Best.HTTP.Hosts.Connections.SupportedProtocols.HTTP){if(this._connection.NegotiationResult!=null)request.SetHeader("Authorization","Bearer "+this._connection.NegotiationResult.AccessToken);if(!string.IsNullOrEmpty(this._playFabId))request.SetHeader("x-ms-client-principal-id",this._playFabId);if(!string.IsNullOrEmpty(this._clientPrincipalId))request.SetHeader("x-functions-key",this._clientPrincipalId);}elseif(Best.HTTP.Hosts.Connections.HTTPProtocolFactory.GetProtocolFromUri(request.Uri)!=Best.HTTP.Hosts.Connections.SupportedProtocols.WebSocket)request.Uri=PrepareUriImpl(request.Uri);}publicUriPrepareUri(Uriuri){if(this._connection.NegotiationResult==null)returnuri;if(uri.Query.StartsWith("??")){UriBuilderbuilder=newUriBuilder(uri);builder.Query=builder.Query.Substring(2);returnbuilder.Uri;}if(Best.HTTP.Hosts.Connections.HTTPProtocolFactory.GetProtocolFromUri(uri)==Best.HTTP.Hosts.Connections.SupportedProtocols.WebSocket)uri=PrepareUriImpl(uri);returnuri;}privateUriPrepareUriImpl(Uriuri){if(this._connection.NegotiationResult!=null&&!string.IsNullOrEmpty(this._connection.NegotiationResult.AccessToken)){stringquery=string.IsNullOrEmpty(uri.Query)?"":uri.Query+"&";UriBuilderuriBuilder=newUriBuilder(uri.Scheme,uri.Host,uri.Port,uri.AbsolutePath,query+"access_token="+this._connection.NegotiationResult.AccessToken);returnuriBuilder.Uri;}returnuri;}publicvoidCancel(){}}}
varhub=newHubConnection(URL,protocol);hub.AuthenticationProvider=newAccessTokenAuthenticatorWithAuzreFunctionAuthorization(hub,"<Play Fab ID>","<Azure Functions Key>");