netCore自定义中间件限制用户同时登录
.netcore中间件的定义很奇怪,不需要继承什么,只需要有一个关键的方法就行。InvokeAsync方法内有一个参数HttpContext 当前请求上下文。再一个就是要有一个RequestDelegate。
直接上代码
private readonly ICache _cache; private readonly RequestDelegate _next; public LoginOneMiddleware(RequestDelegate next, IServiceProvider service) { _next = next; _cache = service.GetRequiredService<ICache>(); } public Task InvokeAsync(HttpContext httpContext) { var user = httpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.UserData); var requestUrl = httpContext.Request.Path.Value; //这里如果请求的是登录的接口,不做判断 if(user != null && !requestUrl.Contains("/login")) { var token = httpContext.Request.Headers[token"].ToString(); var username = user.Value; if(_cache.ContainsKey(username)) { var cachToken = _cache.Get<string>(username); if(token != cachToken) { httpContext.Response.Clear(); httpContext.Response.ContentType = "application/json;charset=utf-8"; var responseStr = "登录已过期"; // httpContext.Response.StatusCode = 401; httpContext.Response.WriteAsync(responseStr); return Task.CompletedTask; } } else { _cache.Add(username, token, 60 * 60 * 24); } } return _next(httpContext); }
说下简单思路,登录的时候把生成的token放到redis里面,把用户名当作key,值就是token。如果key存在就更新,用新的token替换掉。然后中间件这里先获取到当前请求的token和用户名,根据用户名找到redis里面用户名这个key对应的值,和当前的token对比,如果不一致就说明是被覆盖了,这时候返回401,让用户重新登录。
添加好中间件之后,用扩展方法添加中间件
public static IApplicationBuilder UseLogin(this IApplicationBuilder app)
{
return app.UseMiddleware<LoginOneMiddleware>();
}
然后再startup里面添加中间件即可
app.UseLogin();