在API方法之前转换HttpContext.User
我目前有一个.Net核心API应用程序,其中包含一系列API get方法。目前,在每一种方法中,我都需要写这一行:在API方法之前转换HttpContext.User,api,asp.net-core,.net-core,asp.net-core-mvc,asp.net-core-webapi,Api,Asp.net Core,.net Core,Asp.net Core Mvc,Asp.net Core Webapi,我目前有一个.Net核心API应用程序,其中包含一系列API get方法。目前,在每一种方法中,我都需要写这一行: [ProducesResponseType(200, Type = typeof(MetadataAttributeModel))] [ProducesResponseType(400, Type = typeof(ValidationResultModel))] [ProducesResponseType(500, Type = t
[ProducesResponseType(200, Type = typeof(MetadataAttributeModel))]
[ProducesResponseType(400, Type = typeof(ValidationResultModel))]
[ProducesResponseType(500, Type = typeof(ErrorResultModel))]
public ActionResult<MetadataAttributeModel> GetAsync(string name)
{
List<Entities.DocumentAttributeView> attributes = documentAttributeViewRepo.GetByAttributeName(name);
SiteUser currentUser = new SiteUser(db, User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress").Value);
return Unauthorized();
}
蒂亚,
Alex您可以将此逻辑移动到服务:
public class UserService : IUserService
{
private readonly HttpContext context;
private readonly Db db;
public UserService(IHttpContextAccessor context, Db db)
{
this.context = context.HttpContext;
this.db = db;
}
public SiteUser GetUser()
{
return new SiteUser(db, context.User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress").Value);
}
}
在需要时将其注入控制器:
public MyController(IUserService userService) { ... }
在Startup.cs中的ConfigureServices中将其注册为作用域服务,并与IHttpContextAccessor
(应为单例):
public void配置服务(IServiceCollection服务)
{
services.addScope();
services.TryAddSingleton();
}
用于“为每个动作做点什么”的AspNet Mvc机制是
过滤器可以在调用方法之前运行,例如,它们可以设置Http.Context.User
筛选器可以应用于操作、控制器或全局(通过在启动中写入代码)
[SwapUserToAuthorizedDatabaseUser]
public class MyController
{
public IActionResult About() => Ok(User);
}
它将为控制器上的每个操作调用此筛选器:
public class SwapUserToAuthorizedDatabaseUserAttribute : Attribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
SiteUser currentUser = new SiteUser(db, User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress").Value);
if (currentUser == null)
{
context.Result= new RedirectToRouteResult("/Identity/Logout");
}
else
{
var claimsIdentity =
new ClaimsIdentity(
new Claim[]
{
new Claim("Id", currentUser.Id),
new Claim("UserName", currentUser.UserName),
new Claim("WhateverElseYourSiteUserHas", currentUser.Something.ToString()),
}
);
context.HttpContext.User = new ClaimsPrincipal(new[]{claimsIdentity});
}
}
public void OnActionExecuted(ActionExecutedContext context){}
}
如果您不需要覆盖HttpContext.User
,那么使用HttpContext.Items
的代码就少得多:
public class SwapUserToAuthorizedDatabaseUserAttribute : Attribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
context.HttpContext.Items["SiteUser"]= new SiteUser(db, User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress").Value);
}
public void OnActionExecuted(ActionExecutedContext context){}
}
您可以使用iaauthorizationfilter
方法,而不是在每个操作上运行IActionFilter
,该方法具有公共void OnAuthorization(AuthorizationFilterContext context)
方法。这将节省重复调用数据库的时间,但确实意味着您必须将当前用户
缓存在某个地方,大概是在会话
中
问题是,如何访问数据库?如果您通过在启动中添加全局筛选器来添加全局筛选器:
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvc(o=>o.Filters.Add(new SwapUserToAuthorizedDatabaseUserAttribute(provide a db instance here)));
}
然后,您可以为过滤器提供一个构造函数并传入一个数据库。使用DependencyInjection系统时也会出现过载
如果不使用startup方法,则必须进行DIY注入,例如使用静态方法返回DbContext
public class SwapUserToAuthorizedDatabaseUserAttribute : Attribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
context.HttpContext.Items["SiteUser"]= new SiteUser(db, User.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress").Value);
}
public void OnActionExecuted(ActionExecutedContext context){}
}
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvc(o=>o.Filters.Add(new SwapUserToAuthorizedDatabaseUserAttribute(provide a db instance here)));
}