NET6 自定义授权中间件
AuthorizationWithCustMiddleware
/// <summary> /// 自定义授权中间件类:使用 身份验证中间件 存储的身份信息来进行权限验证 /// 一定要先启用 身份验证中间件(app.UseAuthentication()),它会验证请求中的身份信息,并将身份信息存储在HttpContext.User属性中 /// 如果没有启用身份验证中间件,授权中间件将无法获取到身份信息,从而无法进行权限验证。 /// </summary> public class AuthorizationWithCustMiddleware { private readonly RequestDelegate _next; private readonly ILogger<AuthorizationWithCustMiddleware> _logger; /// <summary> /// 1.拥有public构造函数,且该构造函数中至少包含一个类型为RequestDeleGet的参数 /// </summary> /// <param name="next"></param> /// <param name="logger"></param> public AuthorizationWithCustMiddleware(RequestDelegate next, ILogger<AuthorizationWithCustMiddleware> logger) { _next = next; _logger = logger; } /// <summary> /// 2.拥有名为Invoke或InvokeAsync的public方法,该方法必须包含类型为HttpContext的参数,且该参数必须位于第一个位置, 另外返回值必须为Task类型 /// </summary> /// <param name="context"></param> /// <returns></returns> public async Task Invoke(HttpContext context) { // 自定义的授权逻辑 if (!IsUserAuthorized(context)) { await ResetErrorContent(context, 401, "Unauthorized"); return; } var stopwatch = new Stopwatch(); stopwatch.Start(); await _next(context); var code = context.Response.StatusCode; if (code != StatusCodes.Status200OK) { // 没有 var value = context.Response.Headers["WWW-Authenticate"]; await ResetErrorContent(context, code, value); return; } stopwatch.Stop(); _logger.LogInformation($@"接口[{context.Request.Path}] 耗时: {stopwatch}"); } /// <summary> /// 重置错误内容 /// </summary> /// <param name="context"></param> /// <param name="statusCode"></param> /// <param name="message"></param> private async Task ResetErrorContent(HttpContext context, int statusCode, string message) { context.Response.StatusCode = StatusCodes.Status200OK; context.Response.ContentType = "application/json; charset=utf-8"; await context.Response.WriteAsync("{\"Code\": " + statusCode + ", \"Message\": \"" + (message ?? "Unauthorized") + "\"}"); await context.Response.CompleteAsync(); } /// <summary> /// 自定义的授权逻辑 /// </summary> /// <param name="context"></param> /// <returns></returns> private bool IsUserAuthorized(HttpContext context) { // 在这里编写具体的授权逻辑,例如检查用户的角色、权限等 // 返回true表示用户有权限,返回false表示用户无权限 var metada = context?.GetEndpoint()?.Metadata; if (metada == null) return true; // 是否允许匿名访问 var isAllowAnonymous = metada.OfType<AllowAnonymousAttribute>().Any(); // 允许匿名访问则跳过 if (isAllowAnonymous) return true; // 是否需要权限授权 var isAuthoriza = metada.OfType<AuthorizeAttribute>().Any(); // 不需要则跳过 if (!isAuthoriza) return true; // 具体业务逻辑:暂时只根据jwt检查用户信息 //var claims = context?.User?.Claims; //var isAny = claims?.Any(); var jwt = context?.Request?.Headers["Authorization"].ToString(); var isAny = !string.IsNullOrWhiteSpace(jwt); if (isAny == true) return true; return false; } }
MiddlewareExtendsions
/// <summary> /// 简单封装中间件调用 /// </summary> public static class MiddlewareExtendsions { /// <summary> /// 启用自定义授权中间件 /// </summary> /// <param name="app"></param> /// <returns></returns> public static IApplicationBuilder UseAuthorizationWithCust(this IApplicationBuilder app) { return app.UseMiddleware<AuthorizationWithCustMiddleware>(); } }
Program
// 启用身份验证中间件:注意,一定得先启动这个 app.UseAuthentication(); // 启用自定义授权中间件 app.UseAuthorizationWithCust(); // 启用授权中间件 // app.UseAuthentication()是启用身份验证中间件,它会验证请求中的身份信息,并将身份信息存储在HttpContext.User属性中。 // 而app.UseAuthorization()是启用授权中间件,它会检查HttpContext.User中的身份信息是否有访问当前请求所需的权限。 // 一定要先启用身份验证中间件再启用授权中间件,因为授权中间件需要使用身份验证中间件存储的身份信息来进行权限验证。 // 如果没有启用身份验证中间件,授权中间件将无法获取到身份信息,从而无法进行权限验证。 app.UseAuthorization();