asp.net core webapi 并发请求时 怎么保证实时获取的用户信息是此次请求的?

对于并发请求,每个请求会被分配到一个独立的线程或线程池工作线程上。通过 HttpContextAsyncLocal,每个线程都能独立地获取到它自己的上下文数据。由于这些数据是与当前请求相关的,因此在并发请求时不会互相干扰。

在并发请求时,确保每个请求能够实时获取与之相关的用户信息,主要依赖于以下方法:

  • HttpContext.UserASP.NET Core 内置的请求上下文,保证每个请求独立获取用户信息。

  • AsyncLocal:用于在异步环境中传递请求相关的信息,确保跨线程和异步调用时的正确性。

  • AuthorizationFilterContext .HttpContext.Items:通过拦截器缓存用户信息,可以确保所有后续的请求处理都能正确访问用户信息。

  • 分布式缓存或会话存储:用于分布式应用场景,确保不同服务器上的请求能获取到正确的用户信息。

1. 使用 HTTP 请求上下文(如 HttpContext

ASP.NET Core 中,每个请求都是独立的,并且与当前线程绑定。当你发起一个请求时,ASP.NET Core 会将所有的请求上下文信息(包括认证、用户信息等)存储在 HttpContext 中。这意味着即使你有多个并发请求,每个请求的上下文都是独立的,可以保证每个请求都能获取到与该请求相关的用户信息。

获取用户信息:

你可以通过 HttpContext.User 来获取当前请求的用户信息:

cs 复制代码
public class MyController : ControllerBase
{
    public IActionResult Get()
    {
        var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        var username = User.Identity.Name;
        return Ok(new { userId, username });
    }
}

User 属性会在每个请求的上下文中自动填充,在每个请求线程中是独立的,因此不会发生并发请求时的混淆。

2. 使用 AsyncLocal 存储线程相关信息

在某些情况下,你可能需要跨多个方法、类或任务传递请求特定的信息(如用户信息)。AsyncLocal 提供了一种线程和任务绑定的方式,可以确保每个异步操作或线程都能获取到与当前请求相关的信息。

cs 复制代码
public class UserContext
{
    private static AsyncLocal<User> _currentUser = new AsyncLocal<User>();

    public static User CurrentUser
    {
        get => _currentUser.Value;
        set => _currentUser.Value = value;
    }
}

在每个请求的处理过程中,你可以将当前用户信息存储到 AsyncLocal 中,这样即使是异步操作,也能保证用户信息与当前请求相关。

使用方法:

在请求处理中,你可以在认证时设置用户信息:

cs 复制代码
public class MyController : ControllerBase
{
    public IActionResult Get()
    {
        // 假设从某处获取当前用户信息
        var user = new User { UserId = "123", Username = "JohnDoe" };
        UserContext.CurrentUser = user;

        return Ok(UserContext.CurrentUser);
    }
}

这种方法特别适用于需要跨多个异步方法传递用户信息的场景。

3. 使用拦截器IAuthorizationFilter注入用户信息

通过IAuthorizationFilter设置用户信息。这确保每个请求的用户信息都能被正确注入,尤其是在复杂的认证流程中。

cs 复制代码
 public class AuthorizationFilter : IAuthorizationFilter
 {
     public void OnAuthorization(AuthorizationFilterContext context)
     {
         //var user = context.HttpContext.User;
         //if (user == null || !user.HasClaim("role", "Admin"))
         //{
         //    context.Result = new UnauthorizedResult();
         //}
         context.HttpContext.Items["AccountDetail"] = "Admin";
     }
 }

在请求处理中,你可以通过 HttpContext.Items 来获取用户信息:

cs 复制代码
public class MyController : ControllerBase
{
    public IActionResult Get()
    {
        var serviceProvider = HttpContext.RequestServices;
 var account = serviceProvider?.GetRequiredService<IHttpContextAccessor>().HttpContext?.Items["AccountDetail"];
        return Ok(account);
    }
}

注:需提前注入IHttpContextAccessor

cs 复制代码
      // 注册 IHttpContextAccessor
      builder.Services.AddHttpContextAccessor();

4. 使用分布式缓存或会话存储

在分布式应用中,可能无法依赖单一的线程或请求上下文来存储用户信息,这时可以使用分布式缓存(如 Redis)或会话存储来保存每个请求的用户信息。这确保了无论请求在哪个服务器或进程中被处理,用户信息始终能够正确获取。

使用会话存储:

ASP.NET Core 提供了内置的会话机制,可以在请求之间存储用户信息。

cs 复制代码
public class MyController : ControllerBase
{
    public IActionResult Get()
    {
        // 假设你已经将用户信息存入 Session 中
        var userId = HttpContext.Session.GetString("UserId");
        return Ok(new { userId });
    }
}

在中间件或认证过程中,可以设置用户信息到会话:

cs 复制代码
public class UserContextMiddleware
{
    private readonly RequestDelegate _next;

    public UserContextMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var user = new User { UserId = "123", Username = "JohnDoe" };
        context.Session.SetString("UserId", user.UserId);

        await _next(context);
    }
}
相关推荐
浮尘笔记36 分钟前
go语言简单快速的按顺序遍历kv结构(map)
开发语言·后端·golang
老大白菜38 分钟前
使用 Go 语言调用 SiliconFlow 语音生成 API 的脚本,用于将文本转换为 MP3 格式的语音文件。
开发语言·后端·golang
2301_793069821 小时前
前后端分离的网页游戏,后端spring boot,前端vite+vue
前端·后端·vue·springboot·全栈
大得3691 小时前
django配置跨域
后端·python·django
Pandaconda2 小时前
【Golang 面试题】每日 3 题(五十)
开发语言·经验分享·笔记·后端·面试·golang·go
冬天vs不冷2 小时前
Spring排序机制:接口与注解的使用
java·后端·spring
雪球不会消失了3 小时前
SpringBoot中的Javaconfig
java·spring boot·后端
老大白菜10 小时前
DeepSeek API 调用 - Spring Boot 实现
java·spring boot·后端
.Net Core 爱好者13 小时前
基于Flask搭建AI应用,本地私有化部署开源大语言模型
人工智能·后端·python·语言模型·自然语言处理·flask
uhakadotcom13 小时前
LLVM:编译器开发的瑞士军刀
后端·github