ExternalIdentity.BootstrapContext всегда null

В моем текущем приложении я использую идентификацию Owin + Aspnet вместе с поставщиком Microsoft Live OAuth для обработки аутентификации.

Пока все работает нормально, за исключением моих попыток получить удаленный токен, чтобы сохранить его в моей базе данных.

Я нашел в сети некоторую документацию, в которой говорится, что для сохранения "saveBootstrapContext" в web.config я сделал следующее:

<system.identityModel>
<identityConfiguration saveBootstrapContext="true">
  <securityTokenHandlers>
    <securityTokenHandlerConfiguration saveBootstrapContext="true"></securityTokenHandlerConfiguration>
  </securityTokenHandlers>
</identityConfiguration>
</system.identityModel>

Я пробовал только на identityConfiguration тогда только на securityTokenHandlerConfiguration и то и другое вместе, но результат всегда одинаков. В следующем коде externalData.ExternalIdentity.BootstrapContext всегда ноль.

Метод SignIn вызывается внутри метода ExternalLoginCallback, который вызывается промежуточным программным обеспечением.

using System.IdentityModel.Tokens;
using System.Security.Claims;
using System.Web;

// custom namespaces redacted
using Microsoft.AspNet.Identity;
using Microsoft.Owin.Security;

public class AuthManager : IAuthManager
{
    private readonly IUserBusinessLogic userBusinessLogic;

    public AuthManager(IUserBusinessLogic userBusinessLogic)
    {
        this.userBusinessLogic = userBusinessLogic;
    }

    public void SignIn()
    {
        IAuthenticationManager manager = HttpContext.Current.GetOwinContext().Authentication;
        var externalData = manager.GetExternalLoginInfo();

        UserDto user = this.userBusinessLogic.GetUser(externalData.Login.LoginProvider, externalData.Login.ProviderKey);
        var token = ((BootstrapContext)externalData.ExternalIdentity.BootstrapContext).Token;

        if (user == null)
        {
            user = this.userBusinessLogic.AddUser(new UserDto(), externalData.Login.LoginProvider, externalData.Login.ProviderKey, token);
        }

        user.Token = token;

        var claims = new Claim[]
        {
            new Claim(ClaimTypes.NameIdentifier, user.ID.ToString()),
            new Claim(ClaimTypes.UserData, UserData.FromUserDto(user).ToString())
        };

        var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
        var properties = new AuthenticationProperties
        {
            AllowRefresh = true,
            IsPersistent = true
        };

        manager.SignIn(properties, identity);
    }

В некоторых других сообщениях здесь, в SO, говорится о попытке перезапустить IIS, перезагрузить компьютер, очистить куки браузера и перезапустить браузер. Я попробовал все это и все еще ничего. Если я высмеиваю строку токена, все остальное работает правильно.

Сейчас я явно что-то упускаю, но не могу найти в интернете чёткой документации.

Любая помощь очень ценится.

Благодарю.

1 ответ

Решение

Иногда никакая помощь не лучшая помощь, так как я был вынужден копать глубже и глубже, в конечном счете, чтобы найти решение.

Из-за того, что я был в полной растерянности, я смешивал три разные технологии, не понимая всех последствий.

Мой пример использовал конфигурацию WIF в web.config, но затем на стороне кода он использовал Aspnet Identity поверх OWIN (который вообще не использует web.config).

Как только я изложил свои идеи, я понял следующее:

  • WIF был совершенно не нужен, поэтому я избавился от всей этой конфигурации (и от WIF в целом)
  • Поскольку моя проверка подлинности MS выполнялась специальным промежуточным программным обеспечением OWIN, которое его обрабатывает, я должен был понять, как настроить его для получения токена
  • Идентификация Aspnet использовалась только для DefaultAuthenticationTypes статический класс, который предоставляет некоторые строковые константы. Я сохранил это для простоты ради, но я мог также удалить это.

Так что мой переработанный (и рабочий) код выглядит следующим образом. Прежде всего, конфигурация Middleware должна была обеспечить работу MS auth вместе с токеном внутри Startup.cs

app.UseMicrosoftAccountAuthentication(new MicrosoftAccountAuthenticationOptions
{
    ClientId = "myClientId",
    ClientSecret = "myClientSecret",
    Provider = new MicrosoftAccountAuthenticationProvider
    {
        OnAuthenticated = context =>
        {
            // here's the token
            context.Identity.AddClaim(new System.Security.Claims.Claim("AccessToken", context.AccessToken));
            context.Identity.AddClaim(new System.Security.Claims.Claim("FirstName", context.FirstName));
            context.Identity.AddClaim(new System.Security.Claims.Claim("LastName", context.LastName));
            return Task.FromResult(true);
        }
    }
});

Затем вновь SignIn метод:

public void SignIn()
{
    IAuthenticationManager manager = HttpContext.Current.GetOwinContext().Authentication;
    var externalData = manager.GetExternalLoginInfo();

    UserDto user = this.userBusinessLogic.GetUser(externalData.Login.LoginProvider, externalData.Login.ProviderKey);

    if (user == null)
    {
        user = this.userBusinessLogic.AddUser(
            new UserDto
            { 
                FirstName = externalData.ExternalIdentity.Claims.Single(c => c.Type == "FirstName").Value,
                LastName = externalData.ExternalIdentity.Claims.Single(c => c.Type == "LastName").Value
            },
            externalData.Login.LoginProvider,
            externalData.Login.ProviderKey,
            // here's the token claim that I set in the middleware configuration
            externalData.ExternalIdentity.Claims.Single(c => c.Type == "AccessToken").Value);
    }

    var claims = new Claim[]
    {
        new Claim(ClaimTypes.NameIdentifier, user.ID.ToString()),
        new Claim(ClaimTypes.UserData, UserData.FromUserDto(user).ToString()),
        new Claim("AccessToken", user.Token),
        new Claim("FirstName", user.FirstName),
        new Claim("LastName", user.LastName)
    };

    var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
    var properties = new AuthenticationProperties
    {
        AllowRefresh = true,
        IsPersistent = true
    };

    manager.SignIn(properties, identity);
}

Может быть, это было трудно только для меня, но в любом случае здесь я публикую свое решение, надеясь, что оно может сэкономить некоторые головные боли и несколько дней ругательства для одного из разработчиков.

Удачного кодирования ^^

Другие вопросы по тегам