OAuth:ASP.NET Web API User.Identity 不加载由身份验证令牌提供程序设置的声明
OAuth: ASP.NET Web API User.Identity doesn't load claims set by authentication token provider
我正在使用 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());
}
}
我找到了答案。它与控制的依赖性 injection/inversion 无关。我不确定在添加它之前我认为它是如何工作的。
问题与此处描述的类似(但在我的情况下解决方案不同):User (IPrincipal) not avaliable on ApiController's constructor using Web Api 2.1 and Owin
基本上 IPrincipal
无法从 api 控制器的构造函数访问,这就是没有声明(用户尚未通过身份验证)的原因。 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 被调用时填充了声明。
希望这对某人有所帮助!
protected IStorageService StorageService
{
get
{
if (_storageService == null)
{
_storageService = _storageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
}
return _storageService;
}
}
这不是实现 DI 的最佳方法
使用构造函数注入要好得多。
检查 Constructor Injection in C#/Unity?
如果您不熟悉 Unity,请遵循此 link,非常有用:
https://msdn.microsoft.com/en-us/library/dn223671(v=pandp.30).aspx
此致
我正在使用 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());
}
}
我找到了答案。它与控制的依赖性 injection/inversion 无关。我不确定在添加它之前我认为它是如何工作的。
问题与此处描述的类似(但在我的情况下解决方案不同):User (IPrincipal) not avaliable on ApiController's constructor using Web Api 2.1 and Owin
基本上 IPrincipal
无法从 api 控制器的构造函数访问,这就是没有声明(用户尚未通过身份验证)的原因。 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 被调用时填充了声明。
希望这对某人有所帮助!
protected IStorageService StorageService
{
get
{
if (_storageService == null)
{
_storageService = _storageServiceFactory.CreateStorageService(User.Identity as ClaimsIdentity);
}
return _storageService;
}
}
这不是实现 DI 的最佳方法
使用构造函数注入要好得多。 检查 Constructor Injection in C#/Unity? 如果您不熟悉 Unity,请遵循此 link,非常有用: https://msdn.microsoft.com/en-us/library/dn223671(v=pandp.30).aspx
此致