目前还不太建议你使用内置的序列化,因为实在太多功能或方法不支持,详细对比请参考https://docs.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to
授权相关
基于策略授权,我想在座的加班狗都是大同小异,在2.2以前:
public class PolicyHandler : AuthorizationHandler<PolicyRequirement> { /// <summary> /// 授权方式(cookie, bearer, oauth, openid) /// </summary> public IAuthenticationSchemeProvider Schemes { get; set; } private IConfiguration _configuration; /// <summary> /// ctor /// </summary> /// <param></param> /// <param></param> /// <param></param> public PolicyHandler(IConfiguration configuration, IAuthenticationSchemeProvider schemes) { Schemes = schemes; _jwtApp = jwtApp; _configuration = configuration; } /// <summary> /// 授权处理 /// </summary> /// <param></param> /// <param></param> protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement) { var httpContext = (context.Resource as AuthorizationFilterContext).HttpContext; //获取授权方式 var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); if (defaultAuthenticate != null) { //验证签发的用户信息 var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name); if (result.Succeeded) { httpContext.User = result.Principal; //判断是否过期 var expirationTime = DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration).Value); if (expirationTime >= DateTime.UtcNow) { //你的校验方式 //todo context.Succeed(requirement); } else { HandleBlocked(context, requirement); } return; } } HandleBlocked(context, requirement); } /// <summary> /// 验证失败返回 /// </summary> private void HandleBlocked(AuthorizationHandlerContext context, PolicyRequirement requirement) { var authorizationFilterContext = context.Resource as AuthorizationFilterContext; authorizationFilterContext.Result = new Microsoft.AspNetCore.Mvc.JsonResult(new UnAuthorizativeResponse()) { StatusCode = 202 }; //不要调用 context.Fail(),设置为403会显示不了自定义信息,改为Accepted202,由客户端处理,; context.Succeed(requirement); } }
然后发现升级到3.0之后,
var httpContext = (context.Resource as AuthorizationFilterContext).HttpContext;
3.0不再支持返回AuthorizationFilterContext,而是返回的是RouteEndpoint,这句代码就会报错,所以修改的方式就是注入IHttpContextAccessor,从里面获取HttpContext,这里就不用演示了吧。
并修改PolicyHandler校验失败时候调用的方法:
/// <summary> /// 验证失败返回 /// </summary> private void HandleBlocked(AuthorizationHandlerContext context, PolicyRequirement requirement) { context.Fail(); }
并在Startup.ConfigureServices修改
services.AddHttpContextAccessor();
在AddJwtBearer中
.AddJwtBearer(s => { //3、添加 Jwt bearer s.TokenValidationParameters = new TokenValidationParameters { ValidIssuer = issuer, ValidAudience = audience, IssuerSigningKey = key, //允许的服务器时间偏差的偏移量 ClockSkew = TimeSpan.FromSeconds(5), ValidateLifetime = true }; s.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { //Token 过期 if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return Task.CompletedTask; }, OnChallenge = context => { context.HandleResponse(); context.Response.StatusCode = StatusCodes.Status200OK; context.Response.ContentType = "application/json"; //无授权返回自定义信息 context.Response.WriteAsync(JsonConvert.SerializeObject(new UnAuthorizativeResponse())); return Task.CompletedTask; } }; });
UnAuthorizativeResponse 是自定义返回的内容。
Startup.Configure中启用Authentication,注意顺序
app.UseRouting(); //跨域 app.UseCors(one); app.UseCors(two); …… //启用 Authentication app.UseAuthorization(); app.UseAuthentication(); app.UseEndpoints(endpoints => ……
也必须在app.UseRouting和app.UseEndpoints之间。
文件下载
单独封装的HttpContext下载方法:
public static void DownLoadFile(this HttpContext context,string fileName, byte[] fileByte, string contentType = "application/octet-stream") { int bufferSize = 1024; context.Response.ContentType = contentType; context.Response.Headers.Append("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName)); context.Response.Headers.Append("Charset", "utf-8"); context.Response.Headers.Append("Access-Control-Expose-Headers", "Content-Disposition"); //context.Response.Headers.Append("Access-Control-Allow-Origin", "*"); //使用FileStream开始循环读取要下载文件的内容 using (Stream fs = new MemoryStream(fileByte)) { using (context.Response.Body) { long contentLength = fs.Length; context.Response.ContentLength = contentLength; byte[] buffer; long hasRead = 0; while (hasRead < contentLength) { if (context.RequestAborted.IsCancellationRequested) { break; } buffer = new byte[bufferSize]; //从下载文件中读取bufferSize(1024字节)大小的内容到服务器内存中 int currentRead = fs.Read(buffer, 0, bufferSize); context.Response.Body.Write(buffer, 0, currentRead); context.Response.Body.Flush(); hasRead += currentRead; } } } }
下载的时候发现以下错误:Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.