从另一个项目继承(?)IdentityUser
Inherit (?) IdentityUser from another project
我的解决方案中有多个项目,都是 .NET Core 3.1。其中之一是我的核心项目(“A Project”),其中我只有基本模型 classes,没有方法或数据库访问权限。出于演示目的,下面是我的 Address.cs
和 User.cs
文件的简化版本:
public class Address
{
public int Id {get;set;}
public string AddressText {get;set;}
public virtual User User {get;set;}
}
public class User
{
public int UserId {get;set;}
public int UserName {get;set;}
public ICollection<Address> {get;set;}
}
在另一个项目(“B 项目”)中,我将构建实际功能。这个项目已经有 ASP.NET Core Identity 设置和 ApplicationUser
class,它派生自 IdentityUser
并添加了一些自定义属性。
这是我 运行 遇到问题的地方。 Address.User
属性 必须设置为 ApplicationUser
的实例,但 ApplicationUser
位于 B 项目 .
显然,我没有 ASP.NET Core Identity 在我的 A Project 中设置为依赖项,所以我无法移动 ApplicationUser
class进入那个项目。此外,我不能将 ApplicationUser
分配给 Address.User
属性 因为 ApplicationUser
不是从 User
.
派生的
经过一些研究,我发现了一些不同的建议。一个建议是为 ASP.NET 核心身份组件使用一个单独的项目,然后在我的 B 项目 中将其与我的 A 项目 一起引用].另一个灵魂建议创建我自己的 UserStore
。
我不希望我的 A 项目 依赖于任何东西。但是我没有足够的经验来决定哪个选项更适合我的场景。
我以前肯定把自己画在这个特定的角落里!
您可以采取一些策略来解决这个问题,包括您列出的两个。然而,我推荐的方法是使用 interfaces.
总结
您将拥有 IUser
界面 [=] 而不是具体的 User
class 83=] 您将从 项目 A 中的模型中引用它。然后,您将 IUser
界面应用到您的 ApplicationUser
class。这将允许 ApplicationUser
的实例分配给您的,例如Address.User
属性,尽管 Address
并不知道 ApplicationUser
。
例子
在 项目 A 中,您将 classes 更新为如下所示:
public class Address
{
public int Id {get;set;}
public string AddressText {get;set;}
public virtual IUser User {get;set;}
}
public interface IUser
{
int UserId {get;set;}
int UserName {get;set;}
ICollection<Address> {get;set;}
}
然后,在 项目 B 中,您将 IUser
接口应用到您的 ApplicationUser
class 并确保它实现了所需的属性:
public class ApplicationUser: IdentityUser, IUser
{
…
public int UserId {get;set;}
public ICollection<Address> {get;set;}
}
Note: You don’t need to implement UserName
, as that’s already been implemented on IdentityUser
. Though, of course, you can always override the property, should the need arise (e.g., to add validation attributes).
限制
当您访问例如您的 Address.User
属性 时,您将只能访问您在 IUser
上定义的成员。如果您需要访问在 ApplicationUser
或 IdentityUser
上定义的任何其他成员,您首先需要将 IUser
引用转换为 ApplicationUser
;例如,
var user = address.User as ApplicationUser;
var emailConfirmed = user?.EmailConfirmed?? false;
当然,如果您知道您将需要访问这些成员,您只需确保它们已在您的界面上定义,而不必担心关于这个。
注意事项
有几个注意事项值得注意。这些可能不适用于您,但为了完整起见,我想将它们包括在内。
O/RM
正如我在评论中提到的,如果您使用 O/RM 来填充您的模型(例如 Entity Framework (EF) Core),您可能 运行 会遇到识别问题的问题在单独的程序集中具体实现您的接口。这是可以做到的,但它肯定会增加您可能不想与之抗衡的复杂性!但是,如果您手动构建对象图,这将不是问题。
身份与用户模型
IdentityUser
代表当前已验证用户,而不是一般用户参考。例如,在电子商务应用程序中,构造一个 IdentityUser
来引用每个产品的卖家是没有意义的。这里显然存在重叠,使用一个数据源来提供两者就可以了。但也有一些属性(例如 PasswordHash
或 SecurityStamp
)在一般用户模型上填充没有意义。您最终可能会发现这些需求相互冲突。
在上述任一情况下,您可能会发现更容易区分 ApplicationUser
和 User
class。这不是您要求的,但值得考虑。在那种情况下,@RomanKalinchuk 的方法更有意义。尽管如此,即便如此,您仍然可以通过对每个应用相同的 IUser
接口来统一它们,从而确保它们共享一组核心属性。
这只是关于如何解决这个特殊情况的意见
您有一些域 class,例如用户、地址等
你所有的应用程序域属性都在那里
像年龄、性别、名字、姓氏、电子邮件、ID、城市、街道,这些由您的应用程序用户填充,可以在应用程序个人区域查看,例如用于用于交付、通知等
并且您有授权部分。 IdentityUser
class (AspNetUsers table) 包含有关用户凭据(用户名、散列密码等)的数据。此数据的唯一用途是检查当前可用的操作
某些操作或控制器可以用 Authorize
属性标记,并且需要用户在您的系统中进行身份验证。
所以域 User
和授权 IdentityUser
classes 可以完全独立存在,这将满足您的需求
但是如何获取当前域用户呢?
你可以这样做
public interface IUserService
{
User GetUserByEmail(string email);
}
[Authorize]
public class UserController : Controller
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
public User GetCurrentUser()
{
var userName = HttpContext.User.Identity.Name;
return _userService.GetUserByEmail(userName);
}
}
我的解决方案中有多个项目,都是 .NET Core 3.1。其中之一是我的核心项目(“A Project”),其中我只有基本模型 classes,没有方法或数据库访问权限。出于演示目的,下面是我的 Address.cs
和 User.cs
文件的简化版本:
public class Address
{
public int Id {get;set;}
public string AddressText {get;set;}
public virtual User User {get;set;}
}
public class User
{
public int UserId {get;set;}
public int UserName {get;set;}
public ICollection<Address> {get;set;}
}
在另一个项目(“B 项目”)中,我将构建实际功能。这个项目已经有 ASP.NET Core Identity 设置和 ApplicationUser
class,它派生自 IdentityUser
并添加了一些自定义属性。
这是我 运行 遇到问题的地方。 Address.User
属性 必须设置为 ApplicationUser
的实例,但 ApplicationUser
位于 B 项目 .
显然,我没有 ASP.NET Core Identity 在我的 A Project 中设置为依赖项,所以我无法移动 ApplicationUser
class进入那个项目。此外,我不能将 ApplicationUser
分配给 Address.User
属性 因为 ApplicationUser
不是从 User
.
经过一些研究,我发现了一些不同的建议。一个建议是为 ASP.NET 核心身份组件使用一个单独的项目,然后在我的 B 项目 中将其与我的 A 项目 一起引用].另一个灵魂建议创建我自己的 UserStore
。
我不希望我的 A 项目 依赖于任何东西。但是我没有足够的经验来决定哪个选项更适合我的场景。
我以前肯定把自己画在这个特定的角落里!
您可以采取一些策略来解决这个问题,包括您列出的两个。然而,我推荐的方法是使用 interfaces.
总结
您将拥有 IUser
界面 [=] 而不是具体的 User
class 83=] 您将从 项目 A 中的模型中引用它。然后,您将 IUser
界面应用到您的 ApplicationUser
class。这将允许 ApplicationUser
的实例分配给您的,例如Address.User
属性,尽管 Address
并不知道 ApplicationUser
。
例子
在 项目 A 中,您将 classes 更新为如下所示:
public class Address
{
public int Id {get;set;}
public string AddressText {get;set;}
public virtual IUser User {get;set;}
}
public interface IUser
{
int UserId {get;set;}
int UserName {get;set;}
ICollection<Address> {get;set;}
}
然后,在 项目 B 中,您将 IUser
接口应用到您的 ApplicationUser
class 并确保它实现了所需的属性:
public class ApplicationUser: IdentityUser, IUser
{
…
public int UserId {get;set;}
public ICollection<Address> {get;set;}
}
Note: You don’t need to implement
UserName
, as that’s already been implemented onIdentityUser
. Though, of course, you can always override the property, should the need arise (e.g., to add validation attributes).
限制
当您访问例如您的 Address.User
属性 时,您将只能访问您在 IUser
上定义的成员。如果您需要访问在 ApplicationUser
或 IdentityUser
上定义的任何其他成员,您首先需要将 IUser
引用转换为 ApplicationUser
;例如,
var user = address.User as ApplicationUser;
var emailConfirmed = user?.EmailConfirmed?? false;
当然,如果您知道您将需要访问这些成员,您只需确保它们已在您的界面上定义,而不必担心关于这个。
注意事项
有几个注意事项值得注意。这些可能不适用于您,但为了完整起见,我想将它们包括在内。
O/RM
正如我在评论中提到的,如果您使用 O/RM 来填充您的模型(例如 Entity Framework (EF) Core),您可能 运行 会遇到识别问题的问题在单独的程序集中具体实现您的接口。这是可以做到的,但它肯定会增加您可能不想与之抗衡的复杂性!但是,如果您手动构建对象图,这将不是问题。
身份与用户模型
IdentityUser
代表当前已验证用户,而不是一般用户参考。例如,在电子商务应用程序中,构造一个 IdentityUser
来引用每个产品的卖家是没有意义的。这里显然存在重叠,使用一个数据源来提供两者就可以了。但也有一些属性(例如 PasswordHash
或 SecurityStamp
)在一般用户模型上填充没有意义。您最终可能会发现这些需求相互冲突。
在上述任一情况下,您可能会发现更容易区分 ApplicationUser
和 User
class。这不是您要求的,但值得考虑。在那种情况下,@RomanKalinchuk 的方法更有意义。尽管如此,即便如此,您仍然可以通过对每个应用相同的 IUser
接口来统一它们,从而确保它们共享一组核心属性。
这只是关于如何解决这个特殊情况的意见
您有一些域 class,例如用户、地址等 你所有的应用程序域属性都在那里 像年龄、性别、名字、姓氏、电子邮件、ID、城市、街道,这些由您的应用程序用户填充,可以在应用程序个人区域查看,例如用于用于交付、通知等
并且您有授权部分。 IdentityUser
class (AspNetUsers table) 包含有关用户凭据(用户名、散列密码等)的数据。此数据的唯一用途是检查当前可用的操作
某些操作或控制器可以用 Authorize
属性标记,并且需要用户在您的系统中进行身份验证。
所以域 User
和授权 IdentityUser
classes 可以完全独立存在,这将满足您的需求
但是如何获取当前域用户呢?
你可以这样做
public interface IUserService
{
User GetUserByEmail(string email);
}
[Authorize]
public class UserController : Controller
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
public User GetCurrentUser()
{
var userName = HttpContext.User.Identity.Name;
return _userService.GetUserByEmail(userName);
}
}