IHttpContextAccessor在ASP.NET Core中扮演着至关重要的角色。它为开发者提供了一种方便的方式来访问和操作HttpContext对象,从而允许在整个应用程序中轻松地管理和使用HTTP请求和响应的相关信息。下面将深入探讨IHttpContextAccessor的作用、使用方法以及如何通过它来优化Web API的开发流程:
- 访问HttpContext
- 中间件和应用框架中的使用:HttpContext封装了有关个别HTTP请求和响应的所有信息,当收到HTTP请求时,HttpContext实例会进行初始化。这个实例可以通过中间件和应用框架(如Web API控制器、Razor Pages等)访问。
- 读取请求头和响应头:通过HttpRequest和HttpResponse的属性,可以访问和使用HTTP请求和响应的头部信息,这对于处理HTTP通信中的重要元数据至关重要。
- 读取请求正文:HTTP请求可以包含请求正文,例如HTML窗体的内容、UTF-8 JSON有效负载或文件。IHttpContextAccessor允许读取这些数据,这对于处理客户端发送的数据非常重要。
- 中间件中的应用
- 启用请求正文缓冲:在某些情况下,需要多次读取请求正文。IHttpContextAccessor提供了扩展方法来缓冲HTTP请求正文,并支持大型请求正文的处理。
- 处理OPTIONS预检请求:在处理跨域请求时,正确处理OPTIONS预检请求是必要的。通过IHttpContextAccessor,可以设置允许的HTTP方法和头部字段,以确保CORS策略的正确实施。
- 依赖注入
- 注册IHttpContextAccessor服务:在Startup类的ConfigureServices方法中,需要注册IHttpContextAccessor为一个单例服务,这样它就可以在应用程序的其他部分通过依赖注入来使用。
- 使用中间件配置静态HttpContext:通过扩展方法,可以在应用的中间件管道中配置IHttpContextAccessor,以便在整个应用程序中使用HttpContext.Current。
- 安全性考虑
- 避免线程安全问题:HttpContext不是线程安全的,因此在并行任务中直接引用HttpContext数据可能会导致异常。应传递所需的数据而不是HttpContext本身,以避免不安全代码。
- 管理用户身份:IHttpContextAccessor可以用于获取或设置请求的用户,这在处理身份验证和授权时非常有用。
- 功能接口集合
- 访问请求功能:HttpContext提供对当前请求的功能接口集合的访问。这些功能集合是可变的,可以通过中间件来修改,以添加对其他功能的支持。
- 使用高级API:通过BodyReader属性,可以直接访问请求正文,这种高级的、高性能的方法适合那些需要高效处理请求数据的应用场景。
此外,在使用IHttpContextAccessor时,还应注意以下几点:
- 响应写入注意事项:在写入响应正文时,必须注意响应是否已启动,因为一旦响应启动,标头将变为只读。
- 处理取消令牌:在执行长时间运行的任务时,应使用RequestAborted取消令牌,以便在请求中止时能够及时停止任务。
- 异步操作中的应用:在异步操作中,应将IHttpContextAccessor作为参数传递,以确保在等待异步操作完成时不会引用到已经结束的请求上下文。
综上所述,IHttpContextAccessor在ASP. NET Core中提供了一种灵活且强大的机制,用于访问和操作HttpContext实例。它不仅简化了对HTTP请求和响应信息的访问,而且还支持中间件和应用框架中的高级功能。通过合理利用IHttpContextAccessor,开发者可以更加高效地构建和管理Web API,同时也要注意其安全性和性能方面的考量。
1、创建IHttpContextUser接口
public interface IHttpContextUser
{
string Name { get; }
int JwtID { get; }
bool IsAuthenticated();
IEnumerable<Claim> GetClaimsIdentity();
List<string> GetClaimValueByType(string ClaimType);
string GetToken();
List<string> GetUserInfoFromToken(string ClaimType);
#region 拓展(具体使用的)
int userId { get; }
string userName { get; }
string userAccount { get; }
#endregion
}
2、实现接口,创建类AspNetUser
public class AspNetUser : IHttpContextUser
{
private readonly IHttpContextAccessor _accessor;
public AspNetUser(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public string Name => _accessor.HttpContext.User.Identity.Name;
/// <summary>
/// 是jwt的唯一身份标识,主要用来作为一次性的token,从而回避重放攻击,可以用uuid进行设置
/// </summary>
public int JwtID => GetClaimValueByType("jti").FirstOrDefault().ObjToInt();
/// <summary>
/// 是否通过验证
/// </summary>
/// <returns></returns>
public bool IsAuthenticated()
{
return _accessor.HttpContext.User.Identity.IsAuthenticated;
}
/// <summary>
/// 获取token
/// </summary>
/// <returns></returns>
public string GetToken()
{
return _accessor.HttpContext.Request.Headers["Authorization"].ObjToString().Replace("Bearer ", "");
}
public List<string> GetUserInfoFromToken(string ClaimType)
{
var jwtHandler = new JwtSecurityTokenHandler();
if (!string.IsNullOrEmpty(GetToken()))
{
JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(GetToken());
return (from item in jwtToken.Claims
where item.Type == ClaimType
select item.Value).ToList();
}
else
{
return new List<string>() { };
}
}
public IEnumerable<Claim> GetClaimsIdentity()
{
return _accessor.HttpContext.User.Claims;
}
public List<string> GetClaimValueByType(string ClaimType)
{
return (from item in GetClaimsIdentity()
where item.Type == ClaimType
select item.Value).ToList();
}
#region MyRegion 拓展
public int userId => GetClaimValueByType("userId").FirstOrDefault().ObjToInt();//账号id
public string userName => GetClaimValueByType("userName").FirstOrDefault();//姓名
public string userAccount => GetClaimValueByType("userAccount").FirstOrDefault();//登录账号名
#endregion
}
3、注入服务:
#region HttpContext 相关服务
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddScoped<IHttpContextUser, AspNetUser>();
#endregion
4、测试:
4.1、在user的接口那边加了个Test的方法,然后构造函数内添加IHttpContextUser 对象。获取
private readonly Repository<SysUser> _usersRep;
private readonly IHttpContextUser _user;
public SysUserService(Repository<SysUser> usersRep, IHttpContextUser user)
{
_usersRep = usersRep;
_user = user;
}
public async Task<ApiResult> Test()
{
var userid = _user.userId;
var username = _user.userName;
var result = "userid:" + userid + ";username:" + username + ";" ;
return ApiResultHelper.Success(result);
}
4.2、使用swagger或ApiPost调用:(记得携带Token)
这样就可以带出存入Jwt中的相关信息了。
如果需要其他信息,在生成Token时存入即可。
可查看文章:【个人博客搭建】(10)添加JWT-CSDN博客
5、其他
......