[英]Injected IPrincipal is anonymous but Web API Controller User object is authenticated
I'm writing a Web API 2/MVC5 project and I wanted to unit test some code that had to work with an IPrincipal using ASP.Net Identity. 我正在编写Web API 2 / MVC5项目,我想要使用ASP.Net Identity对一些必须与IPrincipal一起工作的代码进行单元测试。 Instead of relying on IPrincipal I wanted to abstract that behind my own IUserService. 我没有依赖IPrincipal,而是想在我自己的IUserService后面抽象出来。 When I look at my injected IUserService
the UserId
and UserName
are null. 当我查看我注入的IUserService
, UserId
和UserName
为null。
public interface IUserService
{
string UserId { get; }
string UserName { get; }
}
The concrete implementation being used is: 使用的具体实现是:
public class UserService : IUserService
{
private IPrincipal _principal;
public UserService(IPrincipal principal)
{
_principal = principal;
}
public string UserName
{
get { return _principal.Identity.GetUserName(); }
}
public string UserId
{
get { return _principal.Identity.GetUserId(); }
}
}
This is using Ninject for dependency injection. 这是使用Ninject进行依赖注入。 Inside NinjectWebCommon.cs I have: 在NinjectWebCommon.cs里面,我有:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IBooksService>().To<BooksService>().InRequestScope();
kernel.Bind<DbContext>().To<ApplicationDbContext>().InRequestScope();
kernel.Bind<ApplicationDbContext>().To<ApplicationDbContext>().InRequestScope();
kernel.Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>().InRequestScope();
kernel.Bind<UserManager<ApplicationUser>>().To<UserManager<ApplicationUser>>().InRequestScope();
kernel.Bind<IBookRepository>().To<BookRepository>().InRequestScope();
kernel.Bind<IUserService>().To<UserService>().InRequestScope();
kernel.Bind<IPrincipal>().ToMethod(ctx => HttpContext.Current.User);
}
If I create a Func<IPrincipal>
and pass ()=>HttpContext.Current.User
everything works fine. 如果我创建一个Func<IPrincipal>
和pass ()=>HttpContext.Current.User
一切正常。 However, I don't see anyone needing to do this and all of the examples suggest this implementation. 但是,我没有看到任何人需要这样做,并且所有示例都表明了这种实现。
Do you ever authenticate the user? 你有没有认证用户? Once the user is authenticated, you need to take care of creating an IIdentity
and an IPrincipal
. 用户通过身份验证后,您需要负责创建IIdentity
和IPrincipal
。 Then, you need to set Thread.CurrentPrincipal
with the IPrincipal
, and you also need to put the IPrincipal
in the current HttpContext
. 然后,您需要使用IPrincipal
设置Thread.CurrentPrincipal
,并且还需要将IPrincipal
放在当前的HttpContext
。
In order for a GenericIdentity
to not be considered anonymous, the Name
property must be a non-empty string. 为了使GenericIdentity
不被视为匿名, Name
属性必须是非空字符串。 In order for a ClaimsIdentity
to not be considered anonymous, the AuthenticationType
property must be a non-null, non-empty string. 为了使ClaimsIdentity
不被视为匿名, AuthenticationType
属性必须是非空的非空字符串。
So, generally, you'll do the following: 所以,通常,您将执行以下操作:
// Perform authentication, usually using some kind of AuthenticationFilter or
// AuthorizationFilter.
// After authenticating, and still within the Auth*Filter,
// I'm going to use a GenericIdentity, but this can be converted to a
// ClaimsIdentity if you're using the default Name claim.
IIdentity identity = new GenericIdentity("myUserName", "myAuthenticationType");
// Again, you could use a ClaimsPrincipal, the concept, however, is the same.
IPrincipal principal = new GenericPrincipal(identity, null /* no roles */);
HttpContext.Current.User = principal;
Thread.CurrentPrincipal = principal;
I did see that you mentioned the new ASP.Net Identity model is being used. 我确实看到你提到正在使用新的ASP.Net Identity模型。 So you'd definitely use ClaimsIdentity
and ClaimsPrincipal
in your code. 因此,您肯定会在代码中使用ClaimsIdentity
和ClaimsPrincipal
。
This is only my guess, but this may be faulty: 这只是我的猜测,但这可能有问题:
kernel.Bind<IUserService>().To<UserService>().InRequestScope();
First use of IUserService can occur before HttpContext.Current.User
is set, so instead of current user, you get null
, because at the moment UserService
was created, HttpContext.Current.User
was null
. 首先使用IUserService可以在设置HttpContext.Current.User
之前进行,因此,当前用户不会获得null
,因为在创建UserService
时, HttpContext.Current.User
为null
。 Since you have InRequestScope()
defined, first created object of UserService
is provided in subsequent uses, so principal is null all the time. 由于您定义了InRequestScope()
,因此在后续使用中提供了UserService
第一个创建对象,因此principal始终为null。
What I would probably do is just use HttpContext
directly: 我可能会做的就是直接使用HttpContext
:
public class HttpContextBasedUserService : IUserService
{
public string UserName
{
get { return HttpContext.Current.User.Identity.GetUserName(); }
}
public string UserId
{
get { return HttpContext.Current.User.Identity.GetUserId(); }
}
}
If you want to use IUserService
in desktop application, create implementation dedicated for desktop use. 如果要在桌面应用程序中使用IUserService
,请创建专用于桌面应用程序的实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.