Операция защиты данных была безуспешной на Azure с использованием OWIN/Katana

Я пытаюсь реализовать сброс пароля на веб-сайте ASP.NET MVC на базе OWIN/Katana, работающем в Azure.

Он работает нормально при локальном запуске, но не работает.

Я создаю UserToken Provider

userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("PasswordReset"))

Но когда я пытаюсь сгенерировать токен следующим образом

var resetToken = await UserManager.GeneratePasswordResetTokenAsync(user.Id);

Я получаю следующее исключение.

System.Security.Cryptography.CryptographicException: операция защиты данных не выполнена. Это может быть вызвано тем, что профиль пользователя не загружен для текущего пользовательского контекста потока, что может быть в том случае, когда поток исполняет роль олицетворения. в System.Security.Cryptography.ProtectedData.Protect(Byte [] userData, Byte [] необязательная энтропия, область DataProtectionScope) в System.Security.Cryptography.DpapiDataProtector.ProviderProtect(Byte [] userData) в System.Security.ataProtector(Byte [] userData) в Microsoft.Owin.Security.DataProtection.DpapiDataProtector.Protect(Byte [] userData) в Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider 2.d__0.MoveNext() --- Конец трассировки стека из предыдущего расположение, в котором было сгенерировано исключение --- в System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (задача-задача) в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (задача-задача) в Microsoft.AspNet.Identity2.Neager.()

Ответ 1

У меня та же проблема, когда я пытаюсь сгенерировать токен с удостоверением ASP.Net и пользовательской функцией входа в систему в веб-API.

"Операция защиты данных была неудачной. Это могло быть вызвано тем, что профиль пользователя не загружен для пользовательского контекста текущего потока, что может быть в случае, когда поток исполняет роль другого".

Я просто создал параметр приложения с именем WEBSITE_LOAD_USER_PROFILE в Microsoft Azure и установил его на 1. Это решение работает для меня.

Вы можете увидеть детали здесь

Ответ 2

Посмотрите мой мой ответ на этот вопрос. Более простое решение может быть достигнуто за счет использования IAppBuilder.GetDataProtectionProvider()

Ответ 3

Я нашел решение. Я не совсем уверен, что для этого нужны все шаги, но теперь мое приложение отлично работает:

1.- Обновите свой web.config для поддержки securityTokenHandlers

<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>

в configSections node. И

  

  <securityTokenHandlers>
    <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler,
                System.IdentityModel, Version=4.0.0.0, Culture=neutral,
                PublicKeyToken=B77A5C561934E089" />

    <add
      type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler,
          System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral,
          PublicKeyToken=B77A5C561934E089">
      <sessionTokenRequirement lifetime="00:30:00"></sessionTokenRequirement>
    </add>
  </securityTokenHandlers>

</identityConfiguration>

как обычный node. 2.- В файле Startup.Auth.cs обновите приложение ConfigureAuth (IAppBuilder) следующим образом:

public void ConfigureAuth(IAppBuilder app)
        {

            UserManagerFactory = () =>
            {
                var userManager = new UserManager<SIAgroUser>(new UserStore<UserType>(new SIAgroUserDbContext()));

                IDataProtectionProvider provider = app.GetDataProtectionProvider();

                //userManager.UserTokenProvider = new Microsoft.AspNet.Identity.Owin.DataProtectorTokenProvider<UserType>(provider.Create("PasswordReset") );
                if (provider != null)
                {
                    userManager.UserTokenProvider = new DataProtectorTokenProvider<UsertType, string>(provider.Create("PasswordReset"));
                }

                return userManager;
            };

            OAuthOptions = new OAuthAuthorizationServerOptions
            {
                TokenEndpointPath = new PathString("/Token"),
                Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
                AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                AllowInsecureHttp = true
            };
            // Enable the application to use a cookie to store information for the signed in user
            // and to use a cookie to temporarily store information about a user logging in with a third party login provider
            app.UseCookieAuthentication(new CookieAuthenticationOptions());
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            // Enable the application to use bearer tokens to authenticate users
            app.UseOAuthBearerTokens(OAuthOptions);

            // Uncomment the following lines to enable logging in with third party login providers
            //app.UseMicrosoftAccountAuthentication(
            //    clientId: "",
            //    clientSecret: "");

            //app.UseTwitterAuthentication(
            //    consumerKey: "",
            //    consumerSecret: "");

            //app.UseFacebookAuthentication(
            //    appId: "",
            //    appSecret: "");

            //app.UseGoogleAuthentication();



        }

3.- Очистите конструктор вашего класса Startup следующим образом:

static Startup()
{
   PublicClientId = "self";
}

Это сработало для меня:) Я надеюсь, что это сработает и для вас.

Ответ 5

Эта ошибка возникает у меня на общем хостинг-провайдере в строке:

var provider = new DpapiDataProtectionProvider("SITENAME");

Решение было довольно простым. Сначала измените приведенную выше строку следующим образом:

var provider = new MachineKeyProtectionProvider();

Затем создайте новый файл, который у меня есть в моем пространстве имен Utilities, например:

using Microsoft.Owin.Security.DataProtection;
using System.Web.Security;

namespace <yournamespace>.Utilities
{
    public class MachineKeyProtectionProvider : IDataProtectionProvider
    {
        public IDataProtector Create(params string[] purposes)
        {
            return new MachineKeyDataProtector(purposes);
        }
    }

    public class MachineKeyDataProtector : IDataProtector
    {
        private readonly string[] _purposes;

        public MachineKeyDataProtector(string[] purposes)
        {
            _purposes = purposes;
        }

        public byte[] Protect(byte[] userData)
        {
            return MachineKey.Protect(userData, _purposes);
        }

        public byte[] Unprotect(byte[] protectedData)
        {
            return MachineKey.Unprotect(protectedData, _purposes);
        }
    }
}

Эт вуаля! Задача решена. Просто помните, что в вашем методе контроллера паролей reset вам также придется использовать этого провайдера, иначе вы получите ошибку Invalid Token.

Ответ 6

Если хост-сервер является виртуальной машиной, это может быть именно то, что написано в сообщении об ошибке. Проверьте, действительно ли для пула приложений в IIS установлено значение Load User Profile установленное в значение true, как исключение:

enter image description here

Ответ 7

Получение UserManager из Owin Pipeline, как установлено в App_Start/Startup.Auth.cs, работает на Azure. Я не уверен, как это работает. DpApi должен работать в Azure с решением, описанным в первой ссылке.

Если у DpApi есть статический ключ машины, установленный в Web.config, все серверные машины смогут расшифровать зашифрованные данные, созданные другой машиной в вашем webfarm, - это понимание этого.

(код, приведенный в стандартном шаблоне - из AccountController.cs)

 private UserManager userManager;
    public UserManager UserManager
    {
        get { return userManager ?? HttpContext.GetOwinContext().GetUserManager<UserManager>(); }
        private set { userManager = value; }
    }