OAuth:ASP.NET Web API User.Identity不加载由身份验证令牌提供程序设置的声明

时间:2015-03-09 19:24:42

标签: authentication asp.net-web-api oauth castle-windsor claims-based-identity

我正在使用OAuth承载身份验证,在Startup.cs中配置如下:

        OAuthBearerAuthenticationOptions oAuthBearerOptions = 
            new OAuthBearerAuthenticationOptions
            {
                AccessTokenProvider = new AccessTokenProvider(),
                AuthenticationMode = AuthenticationMode.Active
            };
        app.UseOAuthBearerAuthentication(oAuthBearerOptions);

...其中AccessTokenProvider实现为:

public class AccessTokenProvider : AuthenticationTokenProvider
{
    public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
    {
        // Internal logic to get data needed for building identity...

        // Create claims identity
        ClaimsIdentity identity = new ClaimsIdentity(identityName);
        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, nameIdentifier));
        // Add other claims

        // Set claims identity
        context.SetTicket(new AuthenticationTicket(identity, new AuthenticationProperties()));
    }
}

如果我在ReceiveAsync的末尾设置断点,我可以验证身份是否已正确构建(有声明)并且已达到SetTicket

但是当我尝试从Web API控制器访问身份时:

public abstract class BaseStorageController : ApiController
{
    protected IStorageService StorageService;

    protected BaseStorageController(IStorageServiceFactory storageServiceFactory)
    {
        StorageService = storageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
    }

}

......身份声明清单是空的!

导致这种情况的原因是什么?

旁注:我不知道这是否相关,但我使用Castle Windsor作为IOC容器将依赖项注入我的控制器(在上面的例子中,IStorageServiceFactory)。在我添加之前,上面似乎有效(声称不是空的)。但是,我没有使用CW来管理与身份验证相关的任何事情。这是api控制器的CW安装程序:

public class ApiControllerInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly().BasedOn<ApiController>().LifestylePerWebRequest());
    }
}

2 个答案:

答案 0 :(得分:3)

我找到了答案。它与依赖注入/控制反转无关。我不确定在添加之前我认为它是如何工作的。

问题与此处描述的类似(但在我的情况下解决方案不同):User (IPrincipal) not avaliable on ApiController's constructor using Web Api 2.1 and Owin

基本上{ap}控制器的构造函数无法访问IPrincipal,这就是没有声明的原因(用户尚未通过身份验证)。 User.Identity只能从控制器的操作中访问,而不能从构造函数中访问。我将基本控制器实现更改为以下内容以解决此问题:

public abstract class BaseStorageController : ApiController
{
    private readonly IStorageServiceFactory _storageServiceFactory;
    private IStorageService _storageService;

    protected BaseStorageController(IStorageServiceFactory storageServiceFactory)
    {
        _storageServiceFactory = storageServiceFactory;
    }

    protected IStorageService StorageService
    {
        get
        {
            if (_storageService == null)
            {
                _storageService = _storageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
            }
            return _storageService;
        }
    }
}

由于StorageService仅通过控制器操作进行访问,因此User.Identity已经过身份验证,并且在StorageService getter被调用时填充了声明。

希望这有助于某人!

答案 1 :(得分:0)

 protected IStorageService StorageService
{
    get
    {
        if (_storageService == null)
        {
            _storageService = _storageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
        }
        return _storageService;
    }
}

这不是实施DI的最佳方法

使用构造函数注入要好得多。 检查Constructor Injection in C#/Unity? 如果你不熟悉Unity,请点击此链接,非常有用: https://msdn.microsoft.com/en-us/library/dn223671(v=pandp.30).aspx

此致