将 ClaimsPrincipal 从控制器传递到服务
Passing ClaimsPrincipal from Controller to Service
我是 .NET Core 的新手,但我正在尝试编写我的代码以尽可能遵守 SOLID 原则。
我有一个场景,在我的网站上注册的用户可能决定使用使用相同电子邮件的 Facebook 帐户登录;这会引发错误,因为我的用户 table 中的电子邮件字段是唯一的。
我的解决方案是创建某种关联 table Users_Facebook 就像这样...
在我注册用户的控制器中;为了获取 userId,我实施了一项服务(A. 检查现有用户的 user_facebook table 或(B. 根据电子邮件将 Facebook userId 与现有用户相关联。
[Route("api/Users")]
[HttpPost]
public async Task<int> RegisterUser()
{
var userId = await userService.GetUserIdAsync(User);
var email = User.Claims.First(e => e.Type == "emails").Value;
var user = await _unitOfWork.Users.GetUserByIdAsync(userId);
// Check contacts to see if one needs to be associated with a user
var contact = await _unitOfWork.Contacts.GetContactByEmail(email);
...
服务片段:
public async Task<string> GetUserIdAsync(ClaimsPrincipal authedUser)
{
var userId = authedUser.Claims.First(e => e.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
var email = authedUser.Claims.First(e => e.Type == "emails").Value;
var identityProvider = authedUser.HasClaim(e => e.Type == "http://schemas.microsoft.com/identity/claims/identityprovider") ?
authedUser.Claims.First(e => e.Type == "http://schemas.microsoft.com/identity/claims/identityprovider").Value : null;
...
我的问题是,这有什么问题吗?我将 ClaimsPrincipal 传递给我的服务可以吗?还是我打破了某种最佳实践?如果我完全离开了,有人可以建议一种更好的方法来做这样的事情吗?
提前致谢
就个人而言,我不会将 ClaimsPrincipal 传递到方法中。而是将 IHttpContextAccessor 传递到服务的构造函数中。这样它就可以通过这样做在 DI 容器中注册:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddHttpContextAccessor();
}
然后在您的服务中 class 像这样注入 IHttpContextAccessor
:
public class MyClass(IHttpContextAccessor context)
{
}
这意味着您可以从 class 中访问当前上下文,而无需通过方法传入。
要访问当前登录的用户,只需像这样访问它:
var username = Context.User.Identity.Name;
我是 .NET Core 的新手,但我正在尝试编写我的代码以尽可能遵守 SOLID 原则。
我有一个场景,在我的网站上注册的用户可能决定使用使用相同电子邮件的 Facebook 帐户登录;这会引发错误,因为我的用户 table 中的电子邮件字段是唯一的。
我的解决方案是创建某种关联 table Users_Facebook 就像这样...
在我注册用户的控制器中;为了获取 userId,我实施了一项服务(A. 检查现有用户的 user_facebook table 或(B. 根据电子邮件将 Facebook userId 与现有用户相关联。
[Route("api/Users")]
[HttpPost]
public async Task<int> RegisterUser()
{
var userId = await userService.GetUserIdAsync(User);
var email = User.Claims.First(e => e.Type == "emails").Value;
var user = await _unitOfWork.Users.GetUserByIdAsync(userId);
// Check contacts to see if one needs to be associated with a user
var contact = await _unitOfWork.Contacts.GetContactByEmail(email);
...
服务片段:
public async Task<string> GetUserIdAsync(ClaimsPrincipal authedUser)
{
var userId = authedUser.Claims.First(e => e.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
var email = authedUser.Claims.First(e => e.Type == "emails").Value;
var identityProvider = authedUser.HasClaim(e => e.Type == "http://schemas.microsoft.com/identity/claims/identityprovider") ?
authedUser.Claims.First(e => e.Type == "http://schemas.microsoft.com/identity/claims/identityprovider").Value : null;
...
我的问题是,这有什么问题吗?我将 ClaimsPrincipal 传递给我的服务可以吗?还是我打破了某种最佳实践?如果我完全离开了,有人可以建议一种更好的方法来做这样的事情吗?
提前致谢
就个人而言,我不会将 ClaimsPrincipal 传递到方法中。而是将 IHttpContextAccessor 传递到服务的构造函数中。这样它就可以通过这样做在 DI 容器中注册:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddHttpContextAccessor();
}
然后在您的服务中 class 像这样注入 IHttpContextAccessor
:
public class MyClass(IHttpContextAccessor context)
{
}
这意味着您可以从 class 中访问当前上下文,而无需通过方法传入。
要访问当前登录的用户,只需像这样访问它:
var username = Context.User.Identity.Name;