在API方法之前转换HttpContext.User

在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

我目前有一个.Net核心API应用程序,其中包含一系列API get方法。目前,在每一种方法中,我都需要写这一行:

        [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)));
}