diff --git "a/\346\242\201\345\220\257\351\221\253/2022-0629 \347\254\254\345\215\201\345\233\233\346\254\241\347\254\224\350\256\260.md" "b/\346\242\201\345\220\257\351\221\253/2022-0629 \347\254\254\345\215\201\345\233\233\346\254\241\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..4f214fc33cf6a934a5deb761b2874ae753934481 --- /dev/null +++ "b/\346\242\201\345\220\257\351\221\253/2022-0629 \347\254\254\345\215\201\345\233\233\346\254\241\347\254\224\350\256\260.md" @@ -0,0 +1,66 @@ +# .NET 6 新特性 —— Random.Shared Intro +``` +最近微软发了一篇 .NET 6 性能提升的博客文章,里面提到了很多有趣的东西,其中有一个是 Random.Shared + +这是一个只读的静态属性,并且是一个线程安全的对象,这个东西可以帮助我们简化 Random 对象的使用 + +Before + +首先我们需要知道 Random 不是线程安全的,所以我们如果要在多线程下用 Random 的话,通常需要考虑线程安全问题 + +既然不是线程安全的,那我们用的时候创建一个就好了,每次都 new 一个,但是这样的话一来代码不够简洁,二来可能会创建比较多的 Random 对象,那么不使用的时候每次 new 要怎么做呢? + +比较简单的做法就是加一个锁,如下所示: + +publicstaticclassRandomGen1 + +{ + +privatestaticRandom _inst = newRandom; + +publicstaticintNext( ) + +{ + +lock(_inst) return_inst.Next; + +} + +} + +但是这样的话会导致获取锁的效率相对来说会比较低,每次还需要去先拿到锁,所以也有别的解法: + +publicstaticclassRandomGen2 + +{ + +privatestaticRandom _global = newRandom; + +[ ThreadStatic] + +privatestaticRandom _local; + +publicstaticintNext( ) + +{ + +Random inst = _local; + +if(inst == null) + +{ + +intseed; + +lock(_global) seed = _global.Next; + +_local = inst = newRandom(seed); + +} + +returninst.Next; + +} + +} +``` \ No newline at end of file diff --git "a/\346\242\201\345\220\257\351\221\253/2022-0701 \347\254\254\345\215\201\344\272\224\346\254\241\347\254\224\350\256\260.md" "b/\346\242\201\345\220\257\351\221\253/2022-0701 \347\254\254\345\215\201\344\272\224\346\254\241\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..817e8cd15d1e81ebd18c09cb870206f96050251a --- /dev/null +++ "b/\346\242\201\345\220\257\351\221\253/2022-0701 \347\254\254\345\215\201\344\272\224\346\254\241\347\254\224\350\256\260.md" @@ -0,0 +1,166 @@ +# 定义审计日志 +```js +using AuditLogDemo.Models; +using AuditLogDemo.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +namespace AuditLogDemo.Fliters +{ + public class AuditLogActionFilter : IAsyncActionFilter + { + /// + /// 审计日志服务对象 + /// + private readonly IAuditLogService _auditLogService; + /// + /// 登录用户 + /// + private readonly ISession _Session; + /// + /// 日志记录 + /// + private readonly ILogger _logger; + + public AuditLogActionFilter( + IAuditLogService auditLogService, + ISession Session, + ILogger logger + ) + { + _Session = Session; + _logger = logger; + _auditLogService = auditLogService; + } + + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + // 判断是否写日志 + if (!ShouldSaveAudit(context)) + { + await next(); + return; + } + //接口Type + var type = (context.ActionDescriptor as ControllerActionDescriptor).ControllerTypeInfo.AsType(); + //方法信息 + var method = (context.ActionDescriptor as ControllerActionDescriptor).MethodInfo; + //方法参数 + var arguments = context.ActionArguments; + //开始计时 + var stopwatch = Stopwatch.StartNew(); + var auditInfo = new AuditInfo + { + UserInfo = _Session?.Id, + ServiceName = type != null ? type.FullName.TruncateWithPostfix(EntityDefault.FieldsLength250) : "", + MethodName = method.Name.TruncateWithPostfix(EntityDefault.FieldsLength250), + ////请求参数转Json + Parameters = JsonConvert.SerializeObject(arguments), + ExecutionTime = DateTime.Now, + BrowserInfo = context.HttpContext.Request.Headers["User-Agent"].ToString().TruncateWithPostfix(EntityDefault.FieldsLength250), + ClientIpAddress = context.HttpContext.Connection.RemoteIpAddress.ToString().TruncateWithPostfix(EntityDefault.FieldsLength50), + //ClientName = _clientInfoProvider.ComputerName.TruncateWithPostfix(EntityDefault.FieldsLength100), + Id = Guid.NewGuid().ToString() + }; + + ActionExecutedContext result = null; + try + { + result = await next(); + if (result.Exception != null && !result.ExceptionHandled) + { + auditInfo.Exception = result.Exception; + } + } + catch (Exception ex) + { + auditInfo.Exception = ex; + throw; + } + finally + { + stopwatch.Stop(); + auditInfo.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + + if (result != null) + { + switch (result.Result) + { + case ObjectResult objectResult: + auditInfo.ReturnValue = JsonConvert.SerializeObject(objectResult.Value); + break; + + case JsonResult jsonResult: + auditInfo.ReturnValue = JsonConvert.SerializeObject(jsonResult.Value); + break; + + case ContentResult contentResult: + auditInfo.ReturnValue = contentResult.Content; + break; + } + } + Console.WriteLine(auditInfo.ToString()); + //保存审计日志 + await _auditLogService.SaveAsync(auditInfo); + } + } + + /// + /// 是否需要记录审计 + /// + /// + /// + private bool ShouldSaveAudit(ActionExecutingContext context) + { + if (!(context.ActionDescriptor is ControllerActionDescriptor)) + return false; + var methodInfo = (context.ActionDescriptor as ControllerActionDescriptor).MethodInfo; + + if (methodInfo == null) + { + return false; + } + + if (!methodInfo.IsPublic) + { + return false; + } + + if (methodInfo.GetCustomAttribute() != null) + { + return true; + } + + if (methodInfo.GetCustomAttribute() != null) + { + return false; + } + + var classType = methodInfo.DeclaringType; + if (classType != null) + { + if (classType.GetTypeInfo().GetCustomAttribute() != null) + { + return true; + } + + if (classType.GetTypeInfo().GetCustomAttribute() != null) + { + return false; + } + } + return false; + } + } +} +``` \ No newline at end of file diff --git "a/\346\242\201\345\220\257\351\221\253/2022-0702 \347\254\254\345\215\201\345\205\255\346\254\241\347\254\224\350\256\260.md" "b/\346\242\201\345\220\257\351\221\253/2022-0702 \347\254\254\345\215\201\345\205\255\346\254\241\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..fc4f3f2c5703e0315199514990e1524b2fb61272 --- /dev/null +++ "b/\346\242\201\345\220\257\351\221\253/2022-0702 \347\254\254\345\215\201\345\205\255\346\254\241\347\254\224\350\256\260.md" @@ -0,0 +1,114 @@ +# 一、验证Token +```js +#region 验证token + +if (!string.IsNullOrEmpty(Token)) + +{ + +int m = new Bll.Api.Common().PUB_VerificationToken(Token); + +if (m <= 0) + +{ + +ReturnStr = "{\"result\":\"" + (int)KeyEnum.AppReturn.失败 + "\",\"msg\":\"登录失效\",\"data\":\"\"}"; + +result = new HttpResponseMessage { Content = new StringContent(ReturnStr, Encoding.GetEncoding("UTF-8"), "application/json") }; + +return result; + +} + +} + +else + +{ + +ReturnStr = "{\"result\":\"" + (int)KeyEnum.AppReturn.失败 + "\",\"msg\":\"token不能为空\",\"data\":\"\"}"; + +result = new HttpResponseMessage { Content = new StringContent(ReturnStr, Encoding.GetEncoding("UTF-8"), "application/json") }; + +return result; + +} + +#endregion 验证token +``` +# 二、调用验证方法 +```js +public int PUB_VerificationToken(string token) + +{ + +int result = 0; + +return 1; + +string secretKey = ConfigurationManager.AppSettings["token_secretKey"].ToString();//加密秘钥 + +if (!string.IsNullOrEmpty(token)) + +{ + +try + +{ + +byte[] key = Encoding.UTF8.GetBytes(secretKey); + +IJsonSerializer serializer = new JsonNetSerializer(); + +IDateTimeProvider provider = new UtcDateTimeProvider(); + +IJwtValidator validator = new JwtValidator(serializer, provider); + +IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder(); + +IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder); + +//解密 + +var json = decoder.DecodeToObject(token, key, verify: true); + +if (json != null) + +{ + +//判断口令过期时间 + +if (json.ExpiryDateTime < DateTime.Now) + +{ + +result = -1; + +} + +else + +{ + +result = 1; + +} + +} + +} + +catch (Exception ex) + +{ + +result = 0; + +} + +} + +return result; + +} +``` \ No newline at end of file