SignalR CryptographicException on AzureWebsites

2019-02-19 03:40发布

问题:

I got this exception with SignalR, deployed in Azure WebSites. It works fine in debug environment. It's SignalR 1.0.1 and I use .NET MVC and WebApi

The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context, which may be the case when the thread is impersonating.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Security.Cryptography.CryptographicException: The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context, which may be the case when the thread is impersonating.

Source Error: 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace: 
[CryptographicException: The data protection operation was unsuccessful. This may have     been caused by not having the user profile loaded for the current thread's user context, which may be the case when the thread is impersonating.]
Microsoft.Owin.Host.SystemWeb.<>c__DisplayClass1.<GetRethrowWithNoStackLossDelegate>b__0(Exception ex) +27
Microsoft.Owin.Host.SystemWeb.Utils.RethrowWithOriginalStack(Exception ex) +15
Microsoft.Owin.Host.SystemWeb.CallContextAsyncResult.End(IAsyncResult result) +47
Microsoft.Owin.Host.SystemWeb.OwinHttpHandler.EndProcessRequest(IAsyncResult result) +7
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9629708
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

Do you have any idea ? Thanks

回答1:

For others coming to this page, I had the same issue but the solution was much simpler. As mentioned in comments above, the accepted answer is bad. Also mentioned is that SignalR defaults to use MachineKeyDataProtector for IProtectedData. MapHubs and MapConnection both call a function InitializeProtectedData which registers MachineKeyDataProtector with the dependency resolver.

My problem was that I was mapping my SignalR routes, and THEN configuring the dependency resolver

RouteTable.Routes.MapConnection<SomeEndpoint>("SomeEndpoint", "SomeEndpointUrl");
GlobalHost.DependencyResolver = 
                     new StructureMapDependencyResolver(ObjectFactory.Container);

So basically the IProtectedData resolver registration done by MapConnection -> InitializeProtectedData was getting blown away when I registered my custom resolver. Simple fix, set the resolver BEFORE mapping the connection.

GlobalHost.DependencyResolver = 
                     new StructureMapDependencyResolver(ObjectFactory.Container);
RouteTable.Routes.MapConnection<SomeEndpoint>("SomeEndpoint", "SomeEndpointUrl");


回答2:

This is the single post that allowed my to resolve this same issue using the following code. dfowlers mention of registering an instance of IProtectedData led me to search and find the definition here.

Note this issue was not encountered when using the Visual Studio development server, but when moving to live. I'm glad I found this post, as I have no idea how I would have been supposed to know to implement IProtectedData otherwise. Maybe there's something deeper in the documentation.

Whether or not this is 100% the correct solution I'm not sure, but this worked for me. I created a class implementing IProtectedData, and then registered that with Ninject.

Class:

using Microsoft.AspNet.SignalR.Infrastructure;

namespace Fwr.DataTeamUploader.Logic
{
    public class ProtectedData : IProtectedData
    {

        // Obviously this isn't doing much to protect the data,
        // assume custom encryption required here

        // To reiterate, no encryption is VERY^4 BAD, see comments.

        public string Protect(string data, string purpose)
        {
            return data;
        }

        public string Unprotect(string protectedValue, string purpose)
        {
            return protectedValue;
        }
    }
}

Ninject registration:

/// <summary>
/// Load your modules or register your services here
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
    ...

    kernel.Bind<IProtectedData>().To<ProtectedData>();

    ...


回答3:

Now in this case, you can now use the extension method MapsHubs() from Microsoft.AspNet.SignalR.SystemWeb package.

MachineKeyProtectedData will be used instead of the default implementation.



回答4:

I do not believe Azure Websites are able to communicate with certificates/crypto API. Similar issues occur when trying to call Azure Management API. The user context under which the Sites are running appears to not have enough permissions to do so.