ExternalIdentity.BootstrapContext始终为null

时间:2015-06-19 13:35:06

标签: c# .net oauth asp.net-identity owin

在我当前的应用程序中,我使用Owin + Aspnet Identity以及Microsoft Live OAuth提供程序来处理身份验证。

到目前为止,一切正常,除了我尝试检索远程令牌,以便将其存储在我的数据库中。

我在网上发现了一些文档,说在web.config中启用“saveBootstrapContext”,所以我做了:

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

我只在identityConfiguration上尝试,然后只在securityTokenHandlerConfiguration上尝试,然后两者一起,但结果始终相同。在以下代码中,externalData.ExternalIdentity.BootstrapContext始终为null。

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,重启机器,清空浏览器cookie并重新启动浏览器。我尝试了所有这些但仍然没有。如果我模拟令牌字符串,其他一切都正常工作。

现在我显然遗漏了一些东西,但我在网上找不到任何明确的文件。

非常感谢任何帮助。

感谢。

1 个答案:

答案 0 :(得分:1)

有时没有任何帮助是最好的帮助,因为我被迫深入挖掘,最终找到解决方案。

正当前提是我完全混乱,我在混合三种不同的技术而不了解所有含义。

我的示例在web.config中使用了WIF配置,但后来在代码端使用了OWIN的Aspnet Identity(根本不使用web.config)。

一旦我理解了我的想法,我意识到以下几点:

  • WIF完全不需要,因此我摆脱了所有配置(以及WIF)
  • 由于我的MS身份验证由处理它的特定OWIN中间件执行,我必须了解如何配置它来检索令牌
  • Aspnet Identity仅用于DefaultAuthenticationTypes静态类,它提供了一些字符串常量。为了简单起见,我保留了它,但我也可以删除它。

所以我的重构(和工作)代码看起来像这样。首先,在Startup.cs

内部,需要使用中间件配置来使MS认证与令牌一起工作
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);
}

也许这对我来说很困难,但无论如何我在这里发布我的解决方案,希望它可以节省一些令人头疼的事情和一些发誓同事的日子。

快乐编码^^