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);
}
Может быть, это было трудно только для меня, но в любом случае здесь я публикую свое решение, надеясь, что оно может сэкономить некоторые головные боли и несколько дней ругательства для одного из разработчиков.
Удачного кодирования ^^