忽略
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
[Route("/check")]
|
||||
public class CheckController: ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Get()
|
||||
{
|
||||
return Ok("ok");
|
||||
}
|
||||
}
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
[Route("/check")]
|
||||
public class CheckController: ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Get()
|
||||
{
|
||||
return Ok("ok");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,124 +1,124 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Hncore.Infrastructure.EF;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
[ApiController]
|
||||
public class HncoreControllerBase : ControllerBase
|
||||
{
|
||||
protected ApiResult Success()
|
||||
{
|
||||
return new ApiResult(ResultCode.C_SUCCESS, "");
|
||||
}
|
||||
|
||||
protected ApiResult Success<T>(T data, string message = "")
|
||||
{
|
||||
return new ApiResult(ResultCode.C_SUCCESS, message) {Data = data};
|
||||
}
|
||||
|
||||
protected ApiResult Error(string message = "")
|
||||
{
|
||||
return new ApiResult(ResultCode.C_UNKNOWN_ERROR, message);
|
||||
}
|
||||
|
||||
protected ApiResult Error(ResultCode code, string message = "")
|
||||
{
|
||||
return new ApiResult(code, message);
|
||||
}
|
||||
|
||||
protected ApiResult UofCommit(string message = "")
|
||||
{
|
||||
RepositoryDbContext.SaveChanges();
|
||||
|
||||
return Success(message);
|
||||
}
|
||||
|
||||
protected ApiResult UofCommit<T>(Func<T> func, string message = "")
|
||||
{
|
||||
RepositoryDbContext.SaveChanges();
|
||||
|
||||
return Success(func(), message);
|
||||
}
|
||||
|
||||
protected async Task<ApiResult> UofCommitAsync(string message = "")
|
||||
{
|
||||
await RepositoryDbContext.SaveChangesAsync();
|
||||
|
||||
return Success(message);
|
||||
}
|
||||
|
||||
protected async Task<ApiResult> UofCommitAsync(IDbContextTransaction trans, string message = "")
|
||||
{
|
||||
await RepositoryDbContext.SaveChangesAsync();
|
||||
|
||||
trans.Commit();
|
||||
|
||||
return Success(message);
|
||||
}
|
||||
|
||||
protected async Task<ApiResult> UofCommitAsync<T>(Func<T> func, string message = "")
|
||||
{
|
||||
await RepositoryDbContext.SaveChangesAsync();
|
||||
|
||||
return Success(func(), message);
|
||||
}
|
||||
|
||||
|
||||
protected DbContext RepositoryDbContext =>
|
||||
Request.HttpContext
|
||||
.RequestServices
|
||||
.GetService<IRepositoryDbContext>()
|
||||
.DbContext;
|
||||
|
||||
protected async Task<string> RenderViewToStringAsync(string viewName, object model = null)
|
||||
{
|
||||
using (var sw = new StringWriter())
|
||||
{
|
||||
var actionContext = new ActionContext(HttpContext, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var viewResult = HttpContext.RequestServices.GetService<IRazorViewEngine>()
|
||||
.FindView(actionContext, viewName, false);
|
||||
|
||||
if (viewResult.View == null)
|
||||
{
|
||||
throw new ArgumentNullException($"未找到视图{viewName}");
|
||||
}
|
||||
|
||||
var viewDictionary =
|
||||
new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
|
||||
{
|
||||
Model = model
|
||||
};
|
||||
|
||||
var viewContext = new ViewContext(
|
||||
actionContext,
|
||||
viewResult.View,
|
||||
viewDictionary,
|
||||
new TempDataDictionary(actionContext.HttpContext,
|
||||
HttpContext.RequestServices.GetService<ITempDataProvider>()),
|
||||
sw,
|
||||
new HtmlHelperOptions()
|
||||
);
|
||||
|
||||
await viewResult.View.RenderAsync(viewContext);
|
||||
|
||||
return sw.ToString().HtmlDecode();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Hncore.Infrastructure.EF;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
[ApiController]
|
||||
public class HncoreControllerBase : ControllerBase
|
||||
{
|
||||
protected ApiResult Success()
|
||||
{
|
||||
return new ApiResult(ResultCode.C_SUCCESS, "");
|
||||
}
|
||||
|
||||
protected ApiResult Success<T>(T data, string message = "")
|
||||
{
|
||||
return new ApiResult(ResultCode.C_SUCCESS, message) {Data = data};
|
||||
}
|
||||
|
||||
protected ApiResult Error(string message = "")
|
||||
{
|
||||
return new ApiResult(ResultCode.C_UNKNOWN_ERROR, message);
|
||||
}
|
||||
|
||||
protected ApiResult Error(ResultCode code, string message = "")
|
||||
{
|
||||
return new ApiResult(code, message);
|
||||
}
|
||||
|
||||
protected ApiResult UofCommit(string message = "")
|
||||
{
|
||||
RepositoryDbContext.SaveChanges();
|
||||
|
||||
return Success(message);
|
||||
}
|
||||
|
||||
protected ApiResult UofCommit<T>(Func<T> func, string message = "")
|
||||
{
|
||||
RepositoryDbContext.SaveChanges();
|
||||
|
||||
return Success(func(), message);
|
||||
}
|
||||
|
||||
protected async Task<ApiResult> UofCommitAsync(string message = "")
|
||||
{
|
||||
await RepositoryDbContext.SaveChangesAsync();
|
||||
|
||||
return Success(message);
|
||||
}
|
||||
|
||||
protected async Task<ApiResult> UofCommitAsync(IDbContextTransaction trans, string message = "")
|
||||
{
|
||||
await RepositoryDbContext.SaveChangesAsync();
|
||||
|
||||
trans.Commit();
|
||||
|
||||
return Success(message);
|
||||
}
|
||||
|
||||
protected async Task<ApiResult> UofCommitAsync<T>(Func<T> func, string message = "")
|
||||
{
|
||||
await RepositoryDbContext.SaveChangesAsync();
|
||||
|
||||
return Success(func(), message);
|
||||
}
|
||||
|
||||
|
||||
protected DbContext RepositoryDbContext =>
|
||||
Request.HttpContext
|
||||
.RequestServices
|
||||
.GetService<IRepositoryDbContext>()
|
||||
.DbContext;
|
||||
|
||||
protected async Task<string> RenderViewToStringAsync(string viewName, object model = null)
|
||||
{
|
||||
using (var sw = new StringWriter())
|
||||
{
|
||||
var actionContext = new ActionContext(HttpContext, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var viewResult = HttpContext.RequestServices.GetService<IRazorViewEngine>()
|
||||
.FindView(actionContext, viewName, false);
|
||||
|
||||
if (viewResult.View == null)
|
||||
{
|
||||
throw new ArgumentNullException($"未找到视图{viewName}");
|
||||
}
|
||||
|
||||
var viewDictionary =
|
||||
new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
|
||||
{
|
||||
Model = model
|
||||
};
|
||||
|
||||
var viewContext = new ViewContext(
|
||||
actionContext,
|
||||
viewResult.View,
|
||||
viewDictionary,
|
||||
new TempDataDictionary(actionContext.HttpContext,
|
||||
HttpContext.RequestServices.GetService<ITempDataProvider>()),
|
||||
sw,
|
||||
new HtmlHelperOptions()
|
||||
);
|
||||
|
||||
await viewResult.View.RenderAsync(viewContext);
|
||||
|
||||
return sw.ToString().HtmlDecode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,35 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Common.DingTalk;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
[Route("/pod/[action]")]
|
||||
public class PodHookController : ControllerBase
|
||||
{
|
||||
[HttpGet, AllowAnonymous]
|
||||
public async Task<IActionResult> PreStop()
|
||||
{
|
||||
LogHelper.Warn("应用即将退出");
|
||||
|
||||
if (EnvironmentVariableHelper.IsAspNetCoreProduction)
|
||||
{
|
||||
await DingTalkHelper.SendMessage(new MarkDownModel()
|
||||
{
|
||||
markdown = new markdown()
|
||||
{
|
||||
title = "应用即将退出",
|
||||
text = "### 应用即将退出\n\nhostname:" + EnvironmentVariableHelper.HostName + "\n\n" +
|
||||
DateTime.Now.Format("yyyy-MM-dd HH:mm:ss")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Common.DingTalk;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
[Route("/pod/[action]")]
|
||||
public class PodHookController : ControllerBase
|
||||
{
|
||||
[HttpGet, AllowAnonymous]
|
||||
public async Task<IActionResult> PreStop()
|
||||
{
|
||||
LogHelper.Warn("应用即将退出");
|
||||
|
||||
if (EnvironmentVariableHelper.IsAspNetCoreProduction)
|
||||
{
|
||||
await DingTalkHelper.SendMessage(new MarkDownModel()
|
||||
{
|
||||
markdown = new markdown()
|
||||
{
|
||||
title = "应用即将退出",
|
||||
text = "### 应用即将退出\n\nhostname:" + EnvironmentVariableHelper.HostName + "\n\n" +
|
||||
DateTime.Now.Format("yyyy-MM-dd HH:mm:ss")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,274 +1,274 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Hncore.Infrastructure.Data;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
|
||||
public class ApiResult
|
||||
{
|
||||
public ApiResult()
|
||||
{
|
||||
|
||||
}
|
||||
public ApiResult(object data):this(ResultCode.C_SUCCESS,"")
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
public ApiResult(ResultCode code = ResultCode.C_SUCCESS, string message = "")
|
||||
{
|
||||
Code = code;
|
||||
Message = message;
|
||||
}
|
||||
[JsonProperty("Code")] public ResultCode Code { get; private set; }
|
||||
|
||||
[JsonProperty("Message")] public string Message { get; private set; } = "";
|
||||
|
||||
[JsonProperty("Data")] public virtual object Data { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ApiResult<T>: ApiResult where T : class, new()
|
||||
{
|
||||
[JsonProperty("Data")] public new T Data { get; set; }
|
||||
|
||||
|
||||
private static readonly Dictionary<Enum, string> Dic;
|
||||
|
||||
static ApiResult()
|
||||
{
|
||||
Dic = ObjectExtension.ToDescriptionDictionary<ResultCode>();
|
||||
}
|
||||
public ApiResult()
|
||||
{
|
||||
|
||||
}
|
||||
public ApiResult(T data) : this(ResultCode.C_SUCCESS, "")
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public ApiResult(ResultCode code = ResultCode.C_SUCCESS, string message = "") : base(code, message)
|
||||
{
|
||||
}
|
||||
|
||||
//public ApiResult(ResultCode code = ResultCode.C_SUCCESS, string message = ""):base(code,message)
|
||||
//{
|
||||
// Code = code;
|
||||
|
||||
// if (string.IsNullOrEmpty(message) && Dic.ContainsKey(Code))
|
||||
// {
|
||||
// Message = Dic[Code];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Message = message;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
//public class ApiResult : ApiResult<object>
|
||||
//{
|
||||
|
||||
// public ApiResult(ResultCode code = ResultCode.C_SUCCESS, string message = "") : base(code, message)
|
||||
// {
|
||||
// }
|
||||
//}
|
||||
|
||||
public class ApiResultPaged<T> : ApiResult<T> where T : class, new()
|
||||
{
|
||||
[JsonProperty("TotalCount")] public int TotalCount { get; set; }
|
||||
|
||||
public ApiResultPaged(ResultCode code = ResultCode.C_SUCCESS, string message = "") : base(code, message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static class PageDataExt
|
||||
{
|
||||
public static ApiResultPaged<List<T>> ToApiResult<T>(this PageData<T> pageData) where T : class, new()
|
||||
{
|
||||
return new ApiResultPaged<List<T>>()
|
||||
{
|
||||
TotalCount = pageData.RowCount,
|
||||
Data = pageData.List
|
||||
};
|
||||
}
|
||||
|
||||
public static ApiResultPaged<List<T2>> ToApiResult<T1,T2>(this PageData<T1> pageData) where T2 : class, new()
|
||||
{
|
||||
return new ApiResultPaged<List<T2>>()
|
||||
{
|
||||
TotalCount = pageData.RowCount,
|
||||
Data = pageData.List.MapsTo<T2>().ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum ResultCode
|
||||
{
|
||||
/// <summary>
|
||||
/// 未知错误
|
||||
/// </summary>
|
||||
[Description("服务正在更新中,请稍后再试")] C_UNKNOWN_ERROR = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 成功
|
||||
/// </summary>
|
||||
[Description("成功")] C_SUCCESS = 10000,
|
||||
|
||||
/// <summary>
|
||||
/// 验证码
|
||||
/// </summary>
|
||||
[Description("验证码错误")] C_VERIFY_CODE_ERROR = 10001,
|
||||
|
||||
/// <summary>
|
||||
/// 参数
|
||||
/// </summary>
|
||||
[Description("服务正在更新中,请稍后再试")] C_PARAM_ERROR = 10002,
|
||||
|
||||
/// <summary>
|
||||
/// 登录名
|
||||
/// </summary>
|
||||
[Description("登录名错误")] C_LONGIN_NAME_ERROR = 10003,
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[Description("密码错误")] C_PASSWORD_ERROR = 10004,
|
||||
|
||||
/// <summary>
|
||||
/// 无效操作
|
||||
/// </summary>
|
||||
[Description("非法操作")] C_INVALID_ERROR = 10005,
|
||||
|
||||
/// <summary>
|
||||
/// 文件
|
||||
/// </summary>
|
||||
[Description("文件错误")] C_FILE_ERROR = 10006,
|
||||
|
||||
/// <summary>
|
||||
/// 已存在错误
|
||||
/// </summary>
|
||||
[Description("资源已存在错误")] C_ALREADY_EXISTS_ERROR = 10007,
|
||||
|
||||
/// <summary>
|
||||
/// 资源无法访问:不是资源的拥有者
|
||||
/// </summary>
|
||||
[Description("不是资源的拥有者,资源无法访问")] C_OWNER_ERROR = 10008,
|
||||
|
||||
/// <summary>
|
||||
/// 资源不存在
|
||||
/// </summary>
|
||||
[Description("资源不存在")] C_NOT_EXISTS_ERROR = 10009,
|
||||
|
||||
/// <summary>
|
||||
/// 新建角色出错
|
||||
/// </summary>
|
||||
[Description("创建角色出错")] C_ROLE_CREATE_ERROR = 10010,
|
||||
|
||||
/// <summary>
|
||||
/// 新建权限出错
|
||||
/// </summary>
|
||||
[Description("新建权限错误")] C_PERMISSION_CREATE_ERROR = 10011,
|
||||
|
||||
/// <summary>
|
||||
/// 绑定角色和权限出错
|
||||
/// </summary>
|
||||
[Description("绑定角色和权限出错")] C_ROLE_PERMISSION_CREATE_ERROR = 10012,
|
||||
|
||||
/// <summary>
|
||||
/// 服务器繁忙,请稍后再试!
|
||||
/// </summary>
|
||||
[Description("服务器繁忙")] C_Server_Is_Busy = 10013,
|
||||
|
||||
/// <summary>
|
||||
/// 访问被禁止
|
||||
/// </summary>
|
||||
[Description("禁止访问")] C_Access_Forbidden = 10014,
|
||||
|
||||
/// <summary>
|
||||
/// 非法操作
|
||||
/// </summary>
|
||||
[Description("非法操作")] C_Illegal_Operation = 10015,
|
||||
|
||||
/// <summary>
|
||||
/// 无效的openID
|
||||
/// </summary>
|
||||
[Description("OpenID无效")] C_OPENID_ERROR = 10016,
|
||||
|
||||
/// <summary>
|
||||
/// 返回错误,但无需理会
|
||||
/// </summary>
|
||||
[Description("可忽略的错误")] C_IGNORE_ERROR = 10017,
|
||||
|
||||
/// <summary>
|
||||
/// 用户信息错误
|
||||
/// </summary>
|
||||
[Description("用户信息错误")] C_USERINFO_ERROR = 10018,
|
||||
|
||||
/// <summary>
|
||||
/// 用户需要认证
|
||||
/// </summary>
|
||||
[Description("用户需要认证")] C_USER_SELECT_ERROR = 10019,
|
||||
|
||||
/// <summary>
|
||||
/// 过期
|
||||
/// </summary>
|
||||
[Description("超时错误")] C_TIMEOUT_ERROR = 10020,
|
||||
|
||||
/// <summary>
|
||||
/// 手机和验证码不匹配
|
||||
/// </summary>
|
||||
[Description("手机和验证码不匹配")] C_PHONE_CODE_ERROR = 10021,
|
||||
|
||||
/// <summary>
|
||||
/// 微信没有选择楼
|
||||
/// </summary>
|
||||
[Description("微信没有选择楼")] C_WX_UNIT_UNSELECT_ERROR = 10022,
|
||||
|
||||
/// <summary>
|
||||
/// 黑名单错误
|
||||
/// </summary>
|
||||
[Description("黑名单错误")] C_BLACKLIST_ERROR = 10023,
|
||||
|
||||
/// <summary>
|
||||
/// 支付失败
|
||||
/// </summary>
|
||||
[Description("支付失败")] C_PAY_FAIL = 10024,
|
||||
|
||||
/// <summary>
|
||||
/// 重复支付
|
||||
/// </summary>
|
||||
[Description("重复支付")] RepeatPay= 10025,
|
||||
|
||||
/// <summary>
|
||||
/// 重定向
|
||||
/// </summary>
|
||||
[Description("重定向")] C_REDIRECT_URL = 100302,
|
||||
|
||||
[Description("用户重定向")] C_USER_REDIRECT_URL = 900302,
|
||||
|
||||
|
||||
[Description("人脸已经存在")] C_FACEKEY_EXIST_ERROR = 900303,
|
||||
|
||||
[Description("人脸角度不正确")] C_FACE_ANGLE_ERROR = 900304,
|
||||
|
||||
[Description("退款失败")] C_PAY_Refund = 900305,
|
||||
|
||||
/// <summary>
|
||||
/// 用户支付中
|
||||
/// </summary>
|
||||
[Description("用户支付中")] C_USERPAYING = 900306,
|
||||
|
||||
|
||||
[Description("审核中")] C_VISITOR_CHECKING = 11001,
|
||||
[Description("已过期")] C_VISITOR_OUTTIME = 11002,
|
||||
[Description("未到期")] C_VISITOR_NOTYETDUE = 11003,
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Hncore.Infrastructure.Data;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
|
||||
public class ApiResult
|
||||
{
|
||||
public ApiResult()
|
||||
{
|
||||
|
||||
}
|
||||
public ApiResult(object data):this(ResultCode.C_SUCCESS,"")
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
public ApiResult(ResultCode code = ResultCode.C_SUCCESS, string message = "")
|
||||
{
|
||||
Code = code;
|
||||
Message = message;
|
||||
}
|
||||
[JsonProperty("Code")] public ResultCode Code { get; private set; }
|
||||
|
||||
[JsonProperty("Message")] public string Message { get; private set; } = "";
|
||||
|
||||
[JsonProperty("Data")] public virtual object Data { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ApiResult<T>: ApiResult where T : class, new()
|
||||
{
|
||||
[JsonProperty("Data")] public new T Data { get; set; }
|
||||
|
||||
|
||||
private static readonly Dictionary<Enum, string> Dic;
|
||||
|
||||
static ApiResult()
|
||||
{
|
||||
Dic = ObjectExtension.ToDescriptionDictionary<ResultCode>();
|
||||
}
|
||||
public ApiResult()
|
||||
{
|
||||
|
||||
}
|
||||
public ApiResult(T data) : this(ResultCode.C_SUCCESS, "")
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public ApiResult(ResultCode code = ResultCode.C_SUCCESS, string message = "") : base(code, message)
|
||||
{
|
||||
}
|
||||
|
||||
//public ApiResult(ResultCode code = ResultCode.C_SUCCESS, string message = ""):base(code,message)
|
||||
//{
|
||||
// Code = code;
|
||||
|
||||
// if (string.IsNullOrEmpty(message) && Dic.ContainsKey(Code))
|
||||
// {
|
||||
// Message = Dic[Code];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Message = message;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
//public class ApiResult : ApiResult<object>
|
||||
//{
|
||||
|
||||
// public ApiResult(ResultCode code = ResultCode.C_SUCCESS, string message = "") : base(code, message)
|
||||
// {
|
||||
// }
|
||||
//}
|
||||
|
||||
public class ApiResultPaged<T> : ApiResult<T> where T : class, new()
|
||||
{
|
||||
[JsonProperty("TotalCount")] public int TotalCount { get; set; }
|
||||
|
||||
public ApiResultPaged(ResultCode code = ResultCode.C_SUCCESS, string message = "") : base(code, message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static class PageDataExt
|
||||
{
|
||||
public static ApiResultPaged<List<T>> ToApiResult<T>(this PageData<T> pageData) where T : class, new()
|
||||
{
|
||||
return new ApiResultPaged<List<T>>()
|
||||
{
|
||||
TotalCount = pageData.RowCount,
|
||||
Data = pageData.List
|
||||
};
|
||||
}
|
||||
|
||||
public static ApiResultPaged<List<T2>> ToApiResult<T1,T2>(this PageData<T1> pageData) where T2 : class, new()
|
||||
{
|
||||
return new ApiResultPaged<List<T2>>()
|
||||
{
|
||||
TotalCount = pageData.RowCount,
|
||||
Data = pageData.List.MapsTo<T2>().ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum ResultCode
|
||||
{
|
||||
/// <summary>
|
||||
/// 未知错误
|
||||
/// </summary>
|
||||
[Description("服务正在更新中,请稍后再试")] C_UNKNOWN_ERROR = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 成功
|
||||
/// </summary>
|
||||
[Description("成功")] C_SUCCESS = 10000,
|
||||
|
||||
/// <summary>
|
||||
/// 验证码
|
||||
/// </summary>
|
||||
[Description("验证码错误")] C_VERIFY_CODE_ERROR = 10001,
|
||||
|
||||
/// <summary>
|
||||
/// 参数
|
||||
/// </summary>
|
||||
[Description("服务正在更新中,请稍后再试")] C_PARAM_ERROR = 10002,
|
||||
|
||||
/// <summary>
|
||||
/// 登录名
|
||||
/// </summary>
|
||||
[Description("登录名错误")] C_LONGIN_NAME_ERROR = 10003,
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[Description("密码错误")] C_PASSWORD_ERROR = 10004,
|
||||
|
||||
/// <summary>
|
||||
/// 无效操作
|
||||
/// </summary>
|
||||
[Description("非法操作")] C_INVALID_ERROR = 10005,
|
||||
|
||||
/// <summary>
|
||||
/// 文件
|
||||
/// </summary>
|
||||
[Description("文件错误")] C_FILE_ERROR = 10006,
|
||||
|
||||
/// <summary>
|
||||
/// 已存在错误
|
||||
/// </summary>
|
||||
[Description("资源已存在错误")] C_ALREADY_EXISTS_ERROR = 10007,
|
||||
|
||||
/// <summary>
|
||||
/// 资源无法访问:不是资源的拥有者
|
||||
/// </summary>
|
||||
[Description("不是资源的拥有者,资源无法访问")] C_OWNER_ERROR = 10008,
|
||||
|
||||
/// <summary>
|
||||
/// 资源不存在
|
||||
/// </summary>
|
||||
[Description("资源不存在")] C_NOT_EXISTS_ERROR = 10009,
|
||||
|
||||
/// <summary>
|
||||
/// 新建角色出错
|
||||
/// </summary>
|
||||
[Description("创建角色出错")] C_ROLE_CREATE_ERROR = 10010,
|
||||
|
||||
/// <summary>
|
||||
/// 新建权限出错
|
||||
/// </summary>
|
||||
[Description("新建权限错误")] C_PERMISSION_CREATE_ERROR = 10011,
|
||||
|
||||
/// <summary>
|
||||
/// 绑定角色和权限出错
|
||||
/// </summary>
|
||||
[Description("绑定角色和权限出错")] C_ROLE_PERMISSION_CREATE_ERROR = 10012,
|
||||
|
||||
/// <summary>
|
||||
/// 服务器繁忙,请稍后再试!
|
||||
/// </summary>
|
||||
[Description("服务器繁忙")] C_Server_Is_Busy = 10013,
|
||||
|
||||
/// <summary>
|
||||
/// 访问被禁止
|
||||
/// </summary>
|
||||
[Description("禁止访问")] C_Access_Forbidden = 10014,
|
||||
|
||||
/// <summary>
|
||||
/// 非法操作
|
||||
/// </summary>
|
||||
[Description("非法操作")] C_Illegal_Operation = 10015,
|
||||
|
||||
/// <summary>
|
||||
/// 无效的openID
|
||||
/// </summary>
|
||||
[Description("OpenID无效")] C_OPENID_ERROR = 10016,
|
||||
|
||||
/// <summary>
|
||||
/// 返回错误,但无需理会
|
||||
/// </summary>
|
||||
[Description("可忽略的错误")] C_IGNORE_ERROR = 10017,
|
||||
|
||||
/// <summary>
|
||||
/// 用户信息错误
|
||||
/// </summary>
|
||||
[Description("用户信息错误")] C_USERINFO_ERROR = 10018,
|
||||
|
||||
/// <summary>
|
||||
/// 用户需要认证
|
||||
/// </summary>
|
||||
[Description("用户需要认证")] C_USER_SELECT_ERROR = 10019,
|
||||
|
||||
/// <summary>
|
||||
/// 过期
|
||||
/// </summary>
|
||||
[Description("超时错误")] C_TIMEOUT_ERROR = 10020,
|
||||
|
||||
/// <summary>
|
||||
/// 手机和验证码不匹配
|
||||
/// </summary>
|
||||
[Description("手机和验证码不匹配")] C_PHONE_CODE_ERROR = 10021,
|
||||
|
||||
/// <summary>
|
||||
/// 微信没有选择楼
|
||||
/// </summary>
|
||||
[Description("微信没有选择楼")] C_WX_UNIT_UNSELECT_ERROR = 10022,
|
||||
|
||||
/// <summary>
|
||||
/// 黑名单错误
|
||||
/// </summary>
|
||||
[Description("黑名单错误")] C_BLACKLIST_ERROR = 10023,
|
||||
|
||||
/// <summary>
|
||||
/// 支付失败
|
||||
/// </summary>
|
||||
[Description("支付失败")] C_PAY_FAIL = 10024,
|
||||
|
||||
/// <summary>
|
||||
/// 重复支付
|
||||
/// </summary>
|
||||
[Description("重复支付")] RepeatPay= 10025,
|
||||
|
||||
/// <summary>
|
||||
/// 重定向
|
||||
/// </summary>
|
||||
[Description("重定向")] C_REDIRECT_URL = 100302,
|
||||
|
||||
[Description("用户重定向")] C_USER_REDIRECT_URL = 900302,
|
||||
|
||||
|
||||
[Description("人脸已经存在")] C_FACEKEY_EXIST_ERROR = 900303,
|
||||
|
||||
[Description("人脸角度不正确")] C_FACE_ANGLE_ERROR = 900304,
|
||||
|
||||
[Description("退款失败")] C_PAY_Refund = 900305,
|
||||
|
||||
/// <summary>
|
||||
/// 用户支付中
|
||||
/// </summary>
|
||||
[Description("用户支付中")] C_USERPAYING = 900306,
|
||||
|
||||
|
||||
[Description("审核中")] C_VISITOR_CHECKING = 11001,
|
||||
[Description("已过期")] C_VISITOR_OUTTIME = 11002,
|
||||
[Description("未到期")] C_VISITOR_NOTYETDUE = 11003,
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,126 +1,126 @@
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求顶级父类
|
||||
/// </summary>
|
||||
public class RequestBase
|
||||
{
|
||||
[JsonProperty("TenantId")]
|
||||
[FromQuery(Name = "TenantId")]
|
||||
public int? __tenantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 隶属物业数据库ID
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int TenantId
|
||||
{
|
||||
get => __tenantId.ToInt();
|
||||
set => __tenantId = value;
|
||||
}
|
||||
|
||||
[JsonProperty("OperaterId")]
|
||||
[FromQuery(Name = "OperaterId")]
|
||||
public int? __operaterId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前操作员数据库ID
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int OperaterId
|
||||
{
|
||||
get => __operaterId.ToInt();
|
||||
set => __operaterId = value;
|
||||
}
|
||||
|
||||
[JsonProperty("ProjectCode")]
|
||||
[FromQuery(Name = "ProjectCode")]
|
||||
public int? __projectCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 隶属项目编码
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int ProjectCode
|
||||
{
|
||||
get => __projectCode.ToInt();
|
||||
set => __projectCode = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 泛型请求父类(主要用于在请求时携带数据)
|
||||
/// </summary>
|
||||
/// <typeparam name="T">携带的数据类型</typeparam>
|
||||
public class RequestBase<T> : RequestBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求携带的数据对象
|
||||
/// </summary>
|
||||
public T Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页请求父类(主要用于分页请求操作)
|
||||
/// </summary>
|
||||
///
|
||||
public class PageRequestBase : RequestBase
|
||||
{
|
||||
[JsonProperty("PageIndex")]
|
||||
[FromQuery(Name = "PageIndex")]
|
||||
public int? __pageIndex { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 当前页码
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int PageIndex
|
||||
{
|
||||
get => __pageIndex.ToInt();
|
||||
set => __pageIndex = value;
|
||||
}
|
||||
|
||||
[JsonProperty("PageSize")]
|
||||
[FromQuery(Name = "PageSize")]
|
||||
public int? __pageSize { get; set; } = 50;
|
||||
|
||||
/// <summary>
|
||||
/// 每页条目数
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int PageSize
|
||||
{
|
||||
get => __pageSize.ToInt();
|
||||
set => __pageSize = value;
|
||||
}
|
||||
|
||||
public string KeyWord { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 泛型分页请求父类(在分页请求的基础之上携带数据)
|
||||
/// </summary>
|
||||
/// <typeparam name="T">携带的数据类型</typeparam>
|
||||
public class PageRequestBase<T> : PageRequestBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求携带的数据对象
|
||||
/// </summary>
|
||||
public T Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 主键ID查询请求类(主要用于根据一个主键ID查询单条数据的情况)
|
||||
/// </summary>
|
||||
public class QueryByIdRequest : RequestBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 记录的数据库主键ID
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
}
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求顶级父类
|
||||
/// </summary>
|
||||
public class RequestBase
|
||||
{
|
||||
[JsonProperty("TenantId")]
|
||||
[FromQuery(Name = "TenantId")]
|
||||
public int? __tenantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 隶属物业数据库ID
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int TenantId
|
||||
{
|
||||
get => __tenantId.ToInt();
|
||||
set => __tenantId = value;
|
||||
}
|
||||
|
||||
[JsonProperty("OperaterId")]
|
||||
[FromQuery(Name = "OperaterId")]
|
||||
public int? __operaterId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前操作员数据库ID
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int OperaterId
|
||||
{
|
||||
get => __operaterId.ToInt();
|
||||
set => __operaterId = value;
|
||||
}
|
||||
|
||||
[JsonProperty("ProjectCode")]
|
||||
[FromQuery(Name = "ProjectCode")]
|
||||
public int? __projectCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 隶属项目编码
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int ProjectCode
|
||||
{
|
||||
get => __projectCode.ToInt();
|
||||
set => __projectCode = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 泛型请求父类(主要用于在请求时携带数据)
|
||||
/// </summary>
|
||||
/// <typeparam name="T">携带的数据类型</typeparam>
|
||||
public class RequestBase<T> : RequestBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求携带的数据对象
|
||||
/// </summary>
|
||||
public T Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页请求父类(主要用于分页请求操作)
|
||||
/// </summary>
|
||||
///
|
||||
public class PageRequestBase : RequestBase
|
||||
{
|
||||
[JsonProperty("PageIndex")]
|
||||
[FromQuery(Name = "PageIndex")]
|
||||
public int? __pageIndex { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 当前页码
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int PageIndex
|
||||
{
|
||||
get => __pageIndex.ToInt();
|
||||
set => __pageIndex = value;
|
||||
}
|
||||
|
||||
[JsonProperty("PageSize")]
|
||||
[FromQuery(Name = "PageSize")]
|
||||
public int? __pageSize { get; set; } = 50;
|
||||
|
||||
/// <summary>
|
||||
/// 每页条目数
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int PageSize
|
||||
{
|
||||
get => __pageSize.ToInt();
|
||||
set => __pageSize = value;
|
||||
}
|
||||
|
||||
public string KeyWord { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 泛型分页请求父类(在分页请求的基础之上携带数据)
|
||||
/// </summary>
|
||||
/// <typeparam name="T">携带的数据类型</typeparam>
|
||||
public class PageRequestBase<T> : PageRequestBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求携带的数据对象
|
||||
/// </summary>
|
||||
public T Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 主键ID查询请求类(主要用于根据一个主键ID查询单条数据的情况)
|
||||
/// </summary>
|
||||
public class QueryByIdRequest : RequestBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 记录的数据库主键ID
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,219 +1,219 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using JWT;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public class ValidatorOption
|
||||
{
|
||||
public bool ValidateLifetime = true;
|
||||
}
|
||||
|
||||
public sealed class EtorJwtValidator : IJwtValidator
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly IDateTimeProvider _dateTimeProvider;
|
||||
|
||||
private readonly ValidatorOption _option;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="JwtValidator" />
|
||||
/// </summary>
|
||||
/// <param name="jsonSerializer">The Json Serializer</param>
|
||||
/// <param name="dateTimeProvider">The DateTime Provider</param>
|
||||
public EtorJwtValidator(IJsonSerializer jsonSerializer, IDateTimeProvider dateTimeProvider,ValidatorOption option)
|
||||
{
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_dateTimeProvider = dateTimeProvider;
|
||||
_option = option;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentException" />
|
||||
/// <exception cref="SignatureVerificationException" />
|
||||
public void Validate(string payloadJson, string decodedCrypto, string decodedSignature)
|
||||
{
|
||||
var ex = GetValidationException(payloadJson, decodedCrypto, decodedSignature);
|
||||
if (ex != null)
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentException" />
|
||||
/// <exception cref="SignatureVerificationException" />
|
||||
public void Validate(string payloadJson, string decodedCrypto, string[] decodedSignatures)
|
||||
{
|
||||
var ex = GetValidationException(payloadJson, decodedCrypto, decodedSignatures);
|
||||
if (ex != null)
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given the JWT, verifies its signature correctness without throwing an exception but returning it instead
|
||||
/// </summary>
|
||||
/// <param name="payloadJson">>An arbitrary payload (already serialized to JSON)</param>
|
||||
/// <param name="decodedCrypto">Decoded body</param>
|
||||
/// <param name="decodedSignature">Decoded signature</param>
|
||||
/// <param name="ex">Validation exception, if any</param>
|
||||
/// <returns>True if exception is JWT is valid and exception is null, otherwise false</returns>
|
||||
public bool TryValidate(string payloadJson, string decodedCrypto, string decodedSignature, out Exception ex)
|
||||
{
|
||||
ex = GetValidationException(payloadJson, decodedCrypto, decodedSignature);
|
||||
return ex is null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given the JWT, verifies its signatures correctness without throwing an exception but returning it instead
|
||||
/// </summary>
|
||||
/// <param name="payloadJson">>An arbitrary payload (already serialized to JSON)</param>
|
||||
/// <param name="decodedCrypto">Decoded body</param>
|
||||
/// <param name="decodedSignature">Decoded signatures</param>
|
||||
/// <param name="ex">Validation exception, if any</param>
|
||||
/// <returns>True if exception is JWT is valid and exception is null, otherwise false</returns>
|
||||
public bool TryValidate(string payloadJson, string decodedCrypto, string[] decodedSignature, out Exception ex)
|
||||
{
|
||||
ex = GetValidationException(payloadJson, decodedCrypto, decodedSignature);
|
||||
return ex is null;
|
||||
}
|
||||
|
||||
private Exception GetValidationException(string payloadJson, string decodedCrypto, string decodedSignature)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(payloadJson))
|
||||
return new ArgumentException(nameof(payloadJson));
|
||||
|
||||
if (String.IsNullOrWhiteSpace(decodedCrypto))
|
||||
return new ArgumentException(nameof(decodedCrypto));
|
||||
|
||||
if (String.IsNullOrWhiteSpace(decodedSignature))
|
||||
return new ArgumentException(nameof(decodedSignature));
|
||||
|
||||
if (!CompareCryptoWithSignature(decodedCrypto, decodedSignature))
|
||||
return new SignatureVerificationException(decodedCrypto, decodedSignature);
|
||||
|
||||
return GetValidationException(payloadJson);
|
||||
}
|
||||
|
||||
private Exception GetValidationException(string payloadJson, string decodedCrypto, string[] decodedSignatures)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(payloadJson))
|
||||
return new ArgumentException(nameof(payloadJson));
|
||||
|
||||
if (String.IsNullOrWhiteSpace(decodedCrypto))
|
||||
return new ArgumentException(nameof(decodedCrypto));
|
||||
|
||||
if (AreAllDecodedSignaturesNullOrWhiteSpace(decodedSignatures))
|
||||
return new ArgumentException(nameof(decodedSignatures));
|
||||
|
||||
if (!IsAnySignatureValid(decodedCrypto, decodedSignatures))
|
||||
return new SignatureVerificationException(decodedCrypto, decodedSignatures);
|
||||
|
||||
return GetValidationException(payloadJson);
|
||||
}
|
||||
|
||||
private Exception GetValidationException(string payloadJson)
|
||||
{
|
||||
if (!_option.ValidateLifetime)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var payloadData = _jsonSerializer.Deserialize<Dictionary<string, object>>(payloadJson);
|
||||
|
||||
var now = _dateTimeProvider.GetNow();
|
||||
var secondsSinceEpoch = UnixEpoch.GetSecondsSince(now);
|
||||
|
||||
return ValidateExpClaim(payloadData, secondsSinceEpoch) ?? ValidateNbfClaim(payloadData, secondsSinceEpoch);
|
||||
}
|
||||
|
||||
private static bool AreAllDecodedSignaturesNullOrWhiteSpace(string[] decodedSignatures) =>
|
||||
decodedSignatures.All(sgn => String.IsNullOrWhiteSpace(sgn));
|
||||
|
||||
private static bool IsAnySignatureValid(string decodedCrypto, string[] decodedSignatures) =>
|
||||
decodedSignatures.Any(decodedSignature => CompareCryptoWithSignature(decodedCrypto, decodedSignature));
|
||||
|
||||
/// <remarks>In the future this method can be opened for extension so made protected virtual</remarks>
|
||||
private static bool CompareCryptoWithSignature(string decodedCrypto, string decodedSignature)
|
||||
{
|
||||
if (decodedCrypto.Length != decodedSignature.Length)
|
||||
return false;
|
||||
|
||||
var decodedCryptoBytes = Encoding.UTF8.GetBytes(decodedCrypto);
|
||||
var decodedSignatureBytes = Encoding.UTF8.GetBytes(decodedSignature);
|
||||
|
||||
byte result = 0;
|
||||
for (var i = 0; i < decodedCrypto.Length; i++)
|
||||
{
|
||||
result |= (byte) (decodedCryptoBytes[i] ^ decodedSignatureBytes[i]);
|
||||
}
|
||||
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the 'exp' claim.
|
||||
/// </summary>
|
||||
/// <remarks>See https://tools.ietf.org/html/rfc7515#section-4.1.4</remarks>
|
||||
/// <exception cref="SignatureVerificationException" />
|
||||
/// <exception cref="TokenExpiredException" />
|
||||
private static Exception ValidateExpClaim(IDictionary<string, object> payloadData, double secondsSinceEpoch)
|
||||
{
|
||||
|
||||
if (!payloadData.TryGetValue("exp", out var expObj))
|
||||
return null;
|
||||
|
||||
if (expObj is null)
|
||||
return new SignatureVerificationException("Claim 'exp' must be a number.");
|
||||
|
||||
double expValue;
|
||||
try
|
||||
{
|
||||
expValue = Convert.ToDouble(expObj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new SignatureVerificationException("Claim 'exp' must be a number.");
|
||||
}
|
||||
|
||||
if (secondsSinceEpoch >= expValue)
|
||||
{
|
||||
return new TokenExpiredException("Token has expired.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the 'nbf' claim.
|
||||
/// </summary>
|
||||
/// <remarks>See https://tools.ietf.org/html/rfc7515#section-4.1.5</remarks>
|
||||
/// <exception cref="SignatureVerificationException" />
|
||||
private static Exception ValidateNbfClaim(IReadOnlyDictionary<string, object> payloadData,
|
||||
double secondsSinceEpoch)
|
||||
{
|
||||
if (!payloadData.TryGetValue("nbf", out var nbfObj))
|
||||
return null;
|
||||
|
||||
if (nbfObj is null)
|
||||
return new SignatureVerificationException("Claim 'nbf' must be a number.");
|
||||
|
||||
double nbfValue;
|
||||
try
|
||||
{
|
||||
nbfValue = Convert.ToDouble(nbfObj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new SignatureVerificationException("Claim 'nbf' must be a number.");
|
||||
}
|
||||
|
||||
if (secondsSinceEpoch < nbfValue)
|
||||
{
|
||||
return new SignatureVerificationException("Token is not yet valid.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using JWT;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public class ValidatorOption
|
||||
{
|
||||
public bool ValidateLifetime = true;
|
||||
}
|
||||
|
||||
public sealed class EtorJwtValidator : IJwtValidator
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly IDateTimeProvider _dateTimeProvider;
|
||||
|
||||
private readonly ValidatorOption _option;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="JwtValidator" />
|
||||
/// </summary>
|
||||
/// <param name="jsonSerializer">The Json Serializer</param>
|
||||
/// <param name="dateTimeProvider">The DateTime Provider</param>
|
||||
public EtorJwtValidator(IJsonSerializer jsonSerializer, IDateTimeProvider dateTimeProvider,ValidatorOption option)
|
||||
{
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_dateTimeProvider = dateTimeProvider;
|
||||
_option = option;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentException" />
|
||||
/// <exception cref="SignatureVerificationException" />
|
||||
public void Validate(string payloadJson, string decodedCrypto, string decodedSignature)
|
||||
{
|
||||
var ex = GetValidationException(payloadJson, decodedCrypto, decodedSignature);
|
||||
if (ex != null)
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentException" />
|
||||
/// <exception cref="SignatureVerificationException" />
|
||||
public void Validate(string payloadJson, string decodedCrypto, string[] decodedSignatures)
|
||||
{
|
||||
var ex = GetValidationException(payloadJson, decodedCrypto, decodedSignatures);
|
||||
if (ex != null)
|
||||
throw ex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given the JWT, verifies its signature correctness without throwing an exception but returning it instead
|
||||
/// </summary>
|
||||
/// <param name="payloadJson">>An arbitrary payload (already serialized to JSON)</param>
|
||||
/// <param name="decodedCrypto">Decoded body</param>
|
||||
/// <param name="decodedSignature">Decoded signature</param>
|
||||
/// <param name="ex">Validation exception, if any</param>
|
||||
/// <returns>True if exception is JWT is valid and exception is null, otherwise false</returns>
|
||||
public bool TryValidate(string payloadJson, string decodedCrypto, string decodedSignature, out Exception ex)
|
||||
{
|
||||
ex = GetValidationException(payloadJson, decodedCrypto, decodedSignature);
|
||||
return ex is null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given the JWT, verifies its signatures correctness without throwing an exception but returning it instead
|
||||
/// </summary>
|
||||
/// <param name="payloadJson">>An arbitrary payload (already serialized to JSON)</param>
|
||||
/// <param name="decodedCrypto">Decoded body</param>
|
||||
/// <param name="decodedSignature">Decoded signatures</param>
|
||||
/// <param name="ex">Validation exception, if any</param>
|
||||
/// <returns>True if exception is JWT is valid and exception is null, otherwise false</returns>
|
||||
public bool TryValidate(string payloadJson, string decodedCrypto, string[] decodedSignature, out Exception ex)
|
||||
{
|
||||
ex = GetValidationException(payloadJson, decodedCrypto, decodedSignature);
|
||||
return ex is null;
|
||||
}
|
||||
|
||||
private Exception GetValidationException(string payloadJson, string decodedCrypto, string decodedSignature)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(payloadJson))
|
||||
return new ArgumentException(nameof(payloadJson));
|
||||
|
||||
if (String.IsNullOrWhiteSpace(decodedCrypto))
|
||||
return new ArgumentException(nameof(decodedCrypto));
|
||||
|
||||
if (String.IsNullOrWhiteSpace(decodedSignature))
|
||||
return new ArgumentException(nameof(decodedSignature));
|
||||
|
||||
if (!CompareCryptoWithSignature(decodedCrypto, decodedSignature))
|
||||
return new SignatureVerificationException(decodedCrypto, decodedSignature);
|
||||
|
||||
return GetValidationException(payloadJson);
|
||||
}
|
||||
|
||||
private Exception GetValidationException(string payloadJson, string decodedCrypto, string[] decodedSignatures)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(payloadJson))
|
||||
return new ArgumentException(nameof(payloadJson));
|
||||
|
||||
if (String.IsNullOrWhiteSpace(decodedCrypto))
|
||||
return new ArgumentException(nameof(decodedCrypto));
|
||||
|
||||
if (AreAllDecodedSignaturesNullOrWhiteSpace(decodedSignatures))
|
||||
return new ArgumentException(nameof(decodedSignatures));
|
||||
|
||||
if (!IsAnySignatureValid(decodedCrypto, decodedSignatures))
|
||||
return new SignatureVerificationException(decodedCrypto, decodedSignatures);
|
||||
|
||||
return GetValidationException(payloadJson);
|
||||
}
|
||||
|
||||
private Exception GetValidationException(string payloadJson)
|
||||
{
|
||||
if (!_option.ValidateLifetime)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var payloadData = _jsonSerializer.Deserialize<Dictionary<string, object>>(payloadJson);
|
||||
|
||||
var now = _dateTimeProvider.GetNow();
|
||||
var secondsSinceEpoch = UnixEpoch.GetSecondsSince(now);
|
||||
|
||||
return ValidateExpClaim(payloadData, secondsSinceEpoch) ?? ValidateNbfClaim(payloadData, secondsSinceEpoch);
|
||||
}
|
||||
|
||||
private static bool AreAllDecodedSignaturesNullOrWhiteSpace(string[] decodedSignatures) =>
|
||||
decodedSignatures.All(sgn => String.IsNullOrWhiteSpace(sgn));
|
||||
|
||||
private static bool IsAnySignatureValid(string decodedCrypto, string[] decodedSignatures) =>
|
||||
decodedSignatures.Any(decodedSignature => CompareCryptoWithSignature(decodedCrypto, decodedSignature));
|
||||
|
||||
/// <remarks>In the future this method can be opened for extension so made protected virtual</remarks>
|
||||
private static bool CompareCryptoWithSignature(string decodedCrypto, string decodedSignature)
|
||||
{
|
||||
if (decodedCrypto.Length != decodedSignature.Length)
|
||||
return false;
|
||||
|
||||
var decodedCryptoBytes = Encoding.UTF8.GetBytes(decodedCrypto);
|
||||
var decodedSignatureBytes = Encoding.UTF8.GetBytes(decodedSignature);
|
||||
|
||||
byte result = 0;
|
||||
for (var i = 0; i < decodedCrypto.Length; i++)
|
||||
{
|
||||
result |= (byte) (decodedCryptoBytes[i] ^ decodedSignatureBytes[i]);
|
||||
}
|
||||
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the 'exp' claim.
|
||||
/// </summary>
|
||||
/// <remarks>See https://tools.ietf.org/html/rfc7515#section-4.1.4</remarks>
|
||||
/// <exception cref="SignatureVerificationException" />
|
||||
/// <exception cref="TokenExpiredException" />
|
||||
private static Exception ValidateExpClaim(IDictionary<string, object> payloadData, double secondsSinceEpoch)
|
||||
{
|
||||
|
||||
if (!payloadData.TryGetValue("exp", out var expObj))
|
||||
return null;
|
||||
|
||||
if (expObj is null)
|
||||
return new SignatureVerificationException("Claim 'exp' must be a number.");
|
||||
|
||||
double expValue;
|
||||
try
|
||||
{
|
||||
expValue = Convert.ToDouble(expObj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new SignatureVerificationException("Claim 'exp' must be a number.");
|
||||
}
|
||||
|
||||
if (secondsSinceEpoch >= expValue)
|
||||
{
|
||||
return new TokenExpiredException("Token has expired.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the 'nbf' claim.
|
||||
/// </summary>
|
||||
/// <remarks>See https://tools.ietf.org/html/rfc7515#section-4.1.5</remarks>
|
||||
/// <exception cref="SignatureVerificationException" />
|
||||
private static Exception ValidateNbfClaim(IReadOnlyDictionary<string, object> payloadData,
|
||||
double secondsSinceEpoch)
|
||||
{
|
||||
if (!payloadData.TryGetValue("nbf", out var nbfObj))
|
||||
return null;
|
||||
|
||||
if (nbfObj is null)
|
||||
return new SignatureVerificationException("Claim 'nbf' must be a number.");
|
||||
|
||||
double nbfValue;
|
||||
try
|
||||
{
|
||||
nbfValue = Convert.ToDouble(nbfObj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new SignatureVerificationException("Claim 'nbf' must be a number.");
|
||||
}
|
||||
|
||||
if (secondsSinceEpoch < nbfValue)
|
||||
{
|
||||
return new SignatureVerificationException("Token is not yet valid.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,50 @@
|
||||
using System;
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public abstract class AuthBase : Attribute, IAuthorizationFilter, IResourceFilter
|
||||
{
|
||||
public abstract void OnAuthorization(AuthorizationFilterContext context);
|
||||
|
||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||
{
|
||||
if (!context.HasPassed() && !context.AllowAnonymous())
|
||||
{
|
||||
context.Reject();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内部接口签名
|
||||
/// </summary>
|
||||
/// <param name="timestamp"></param>
|
||||
/// <param name="randomstr"></param>
|
||||
/// <returns></returns>
|
||||
public static string CreateInternalApiSign(long timestamp, string randomstr)
|
||||
{
|
||||
string secret =
|
||||
"1CD985F202645678FF1CE16BC14BCB9E.74562B91A1E851E9CEC9DA8BCE313DFE.EA6B2EFBDD4255A9F1B3BBC6399B58F4";
|
||||
|
||||
return SecurityHelper.GetMd5Hash($"{timestamp}{randomstr}{secret}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建第三方开放接口签名
|
||||
/// </summary>
|
||||
/// <param name="timestamp"></param>
|
||||
/// <param name="randomstr"></param>
|
||||
/// <param name="appKey"></param>
|
||||
/// <returns></returns>
|
||||
public static string CreateOpenApiSign(long timestamp, string randomstr, string appKey)
|
||||
{
|
||||
return SecurityHelper.GetMd5Hash($"{timestamp}{randomstr}{appKey}");
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public abstract class AuthBase : Attribute, IAuthorizationFilter, IResourceFilter
|
||||
{
|
||||
public abstract void OnAuthorization(AuthorizationFilterContext context);
|
||||
|
||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||
{
|
||||
if (!context.HasPassed() && !context.AllowAnonymous())
|
||||
{
|
||||
context.Reject();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内部接口签名
|
||||
/// </summary>
|
||||
/// <param name="timestamp"></param>
|
||||
/// <param name="randomstr"></param>
|
||||
/// <returns></returns>
|
||||
public static string CreateInternalApiSign(long timestamp, string randomstr)
|
||||
{
|
||||
string secret =
|
||||
"1CD985F202645678FF1CE16BC14BCB9E.74562B91A1E851E9CEC9DA8BCE313DFE.EA6B2EFBDD4255A9F1B3BBC6399B58F4";
|
||||
|
||||
return SecurityHelper.GetMd5Hash($"{timestamp}{randomstr}{secret}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建第三方开放接口签名
|
||||
/// </summary>
|
||||
/// <param name="timestamp"></param>
|
||||
/// <param name="randomstr"></param>
|
||||
/// <param name="appKey"></param>
|
||||
/// <returns></returns>
|
||||
public static string CreateOpenApiSign(long timestamp, string randomstr, string appKey)
|
||||
{
|
||||
return SecurityHelper.GetMd5Hash($"{timestamp}{randomstr}{appKey}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,180 +1,180 @@
|
||||
using System.Linq;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public static class HttpContextExt
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否允许匿名访问
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool AllowAnonymous(this AuthorizationFilterContext context)
|
||||
{
|
||||
if (context.HttpContext.Items.ContainsKey("AllowAnonymous")
|
||||
&& context.HttpContext.Items["AllowAnonymous"].ToBool())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.Filters.Any(item => item is IAllowAnonymousFilter))
|
||||
{
|
||||
context.HttpContext.Items["AllowAnonymous"] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许匿名访问
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool AllowAnonymous(this ResourceExecutingContext context)
|
||||
{
|
||||
if (context.HttpContext.Items.ContainsKey("AllowAnonymous")
|
||||
&& context.HttpContext.Items["AllowAnonymous"].ToBool())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.Filters.Any(item => item is IAllowAnonymousFilter))
|
||||
{
|
||||
context.HttpContext.Items["AllowAnonymous"] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否已通过验证
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool HasPassed(this AuthorizationFilterContext context)
|
||||
{
|
||||
if (context.HttpContext.Items.ContainsKey("AuthPassed") && context.HttpContext.Items["AuthPassed"].ToBool())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否已通过验证
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool HasPassed(this ResourceExecutingContext context)
|
||||
{
|
||||
if (context.HttpContext.Items.ContainsKey("AuthPassed") && context.HttpContext.Items["AuthPassed"].ToBool())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过验证
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="filterName">过滤器名称</param>
|
||||
/// <returns></returns>
|
||||
public static void SetPassed(this AuthorizationFilterContext context, string filterName)
|
||||
{
|
||||
context.HttpContext.Items["AuthPassed"] = true;
|
||||
context.HttpContext.Items["AuthPassedFilterName"] = filterName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝通过
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="reason">拒绝原因</param>
|
||||
public static void Reject(this AuthorizationFilterContext context, string reason = "")
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = 401;
|
||||
context.Result = new JsonResult(new ApiResult(ResultCode.C_Access_Forbidden, reason));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝通过并跳转
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="reason"></param>
|
||||
public static void RejectToRedirect(this AuthorizationFilterContext context, string url = "")
|
||||
{
|
||||
//context.HttpContext.Response.StatusCode = 401;
|
||||
context.Result = new RedirectResult(url);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝通过
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="reason">拒绝原因</param>
|
||||
public static void Reject(this ResourceExecutingContext context, string reason = "")
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = 401;
|
||||
context.Result = new JsonResult(new ApiResult(ResultCode.C_Access_Forbidden, reason));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含内部调用验证信息
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasInternalApiAuthInfo(this AuthorizationFilterContext context)
|
||||
{
|
||||
if (!context.HttpContext.Request.Headers.ContainsKey("timestamp")
|
||||
|| !context.HttpContext.Request.Headers.ContainsKey("randomstr")
|
||||
|| !context.HttpContext.Request.Headers.ContainsKey("internalsign"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含第三方开放验证信息
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasOpenApiAuthInfo(this AuthorizationFilterContext context)
|
||||
{
|
||||
if (!context.HttpContext.Request.Headers.ContainsKey("timestamp")
|
||||
|| !context.HttpContext.Request.Headers.ContainsKey("randomstr")
|
||||
|| !context.HttpContext.Request.Headers.ContainsKey("appid")
|
||||
|| !context.HttpContext.Request.Headers.ContainsKey("sign"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含token验证信息
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasTokenAuthInfo(this AuthorizationFilterContext context)
|
||||
{
|
||||
if (!context.HttpContext.Request.Headers.ContainsKey("token")&&!context.HttpContext.Request.Cookies.ContainsKey("token"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
using System.Linq;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public static class HttpContextExt
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否允许匿名访问
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool AllowAnonymous(this AuthorizationFilterContext context)
|
||||
{
|
||||
if (context.HttpContext.Items.ContainsKey("AllowAnonymous")
|
||||
&& context.HttpContext.Items["AllowAnonymous"].ToBool())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.Filters.Any(item => item is IAllowAnonymousFilter))
|
||||
{
|
||||
context.HttpContext.Items["AllowAnonymous"] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许匿名访问
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool AllowAnonymous(this ResourceExecutingContext context)
|
||||
{
|
||||
if (context.HttpContext.Items.ContainsKey("AllowAnonymous")
|
||||
&& context.HttpContext.Items["AllowAnonymous"].ToBool())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.Filters.Any(item => item is IAllowAnonymousFilter))
|
||||
{
|
||||
context.HttpContext.Items["AllowAnonymous"] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否已通过验证
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool HasPassed(this AuthorizationFilterContext context)
|
||||
{
|
||||
if (context.HttpContext.Items.ContainsKey("AuthPassed") && context.HttpContext.Items["AuthPassed"].ToBool())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否已通过验证
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool HasPassed(this ResourceExecutingContext context)
|
||||
{
|
||||
if (context.HttpContext.Items.ContainsKey("AuthPassed") && context.HttpContext.Items["AuthPassed"].ToBool())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过验证
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="filterName">过滤器名称</param>
|
||||
/// <returns></returns>
|
||||
public static void SetPassed(this AuthorizationFilterContext context, string filterName)
|
||||
{
|
||||
context.HttpContext.Items["AuthPassed"] = true;
|
||||
context.HttpContext.Items["AuthPassedFilterName"] = filterName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝通过
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="reason">拒绝原因</param>
|
||||
public static void Reject(this AuthorizationFilterContext context, string reason = "")
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = 401;
|
||||
context.Result = new JsonResult(new ApiResult(ResultCode.C_Access_Forbidden, reason));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝通过并跳转
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="reason"></param>
|
||||
public static void RejectToRedirect(this AuthorizationFilterContext context, string url = "")
|
||||
{
|
||||
//context.HttpContext.Response.StatusCode = 401;
|
||||
context.Result = new RedirectResult(url);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拒绝通过
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="reason">拒绝原因</param>
|
||||
public static void Reject(this ResourceExecutingContext context, string reason = "")
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = 401;
|
||||
context.Result = new JsonResult(new ApiResult(ResultCode.C_Access_Forbidden, reason));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含内部调用验证信息
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasInternalApiAuthInfo(this AuthorizationFilterContext context)
|
||||
{
|
||||
if (!context.HttpContext.Request.Headers.ContainsKey("timestamp")
|
||||
|| !context.HttpContext.Request.Headers.ContainsKey("randomstr")
|
||||
|| !context.HttpContext.Request.Headers.ContainsKey("internalsign"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含第三方开放验证信息
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasOpenApiAuthInfo(this AuthorizationFilterContext context)
|
||||
{
|
||||
if (!context.HttpContext.Request.Headers.ContainsKey("timestamp")
|
||||
|| !context.HttpContext.Request.Headers.ContainsKey("randomstr")
|
||||
|| !context.HttpContext.Request.Headers.ContainsKey("appid")
|
||||
|| !context.HttpContext.Request.Headers.ContainsKey("sign"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含token验证信息
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasTokenAuthInfo(this AuthorizationFilterContext context)
|
||||
{
|
||||
if (!context.HttpContext.Request.Headers.ContainsKey("token")&&!context.HttpContext.Request.Cookies.ContainsKey("token"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +1,70 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Data;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public class InternalApiAuthAttribute : AuthBase,IOrderedFilter
|
||||
{
|
||||
public int Order =>0;
|
||||
|
||||
public override void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
|
||||
if (context.AllowAnonymous()
|
||||
|| context.HasPassed()
|
||||
|| !context.HasInternalApiAuthInfo())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long.TryParse(context.HttpContext.Request.Headers["timestamp"], out long timestamp);
|
||||
string randomstr = context.HttpContext.Request.Headers["randomstr"];
|
||||
string sign = context.HttpContext.Request.Headers["internalsign"];
|
||||
|
||||
if (EnvironmentVariableHelper.IsAspNetCoreProduction)
|
||||
{
|
||||
long secondDiff = DateTimeHelper.ToUnixTimestamp(DateTime.Now) - timestamp;
|
||||
|
||||
if (secondDiff > 600 || secondDiff < -600)
|
||||
{
|
||||
context.Reject("时间戳已过期");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!String.Equals(sign, AuthBase.CreateInternalApiSign(timestamp, randomstr)
|
||||
, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
context.Reject("签名错误");
|
||||
}
|
||||
|
||||
context.SetPassed("InternalApiAuth");
|
||||
}
|
||||
}
|
||||
|
||||
public static class InternalApiAuthExt
|
||||
{
|
||||
public static HttpClient CreateInternalAuthClient(this IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
var httpclient = httpClientFactory.CreateClient(TimeSpan.FromSeconds(10));
|
||||
|
||||
long timestamp = DateTimeHelper.ToUnixTimestamp(DateTime.Now);
|
||||
string randomstr = Guid.NewGuid().ToString();
|
||||
|
||||
var sign = AuthBase.CreateInternalApiSign(timestamp, randomstr);
|
||||
|
||||
httpclient.DefaultRequestHeaders.Add("timestamp", timestamp.ToString());
|
||||
httpclient.DefaultRequestHeaders.Add("randomstr", randomstr);
|
||||
httpclient.DefaultRequestHeaders.Add("internalsign", sign);
|
||||
|
||||
return httpclient;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Data;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public class InternalApiAuthAttribute : AuthBase,IOrderedFilter
|
||||
{
|
||||
public int Order =>0;
|
||||
|
||||
public override void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
|
||||
if (context.AllowAnonymous()
|
||||
|| context.HasPassed()
|
||||
|| !context.HasInternalApiAuthInfo())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long.TryParse(context.HttpContext.Request.Headers["timestamp"], out long timestamp);
|
||||
string randomstr = context.HttpContext.Request.Headers["randomstr"];
|
||||
string sign = context.HttpContext.Request.Headers["internalsign"];
|
||||
|
||||
if (EnvironmentVariableHelper.IsAspNetCoreProduction)
|
||||
{
|
||||
long secondDiff = DateTimeHelper.ToUnixTimestamp(DateTime.Now) - timestamp;
|
||||
|
||||
if (secondDiff > 600 || secondDiff < -600)
|
||||
{
|
||||
context.Reject("时间戳已过期");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!String.Equals(sign, AuthBase.CreateInternalApiSign(timestamp, randomstr)
|
||||
, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
context.Reject("签名错误");
|
||||
}
|
||||
|
||||
context.SetPassed("InternalApiAuth");
|
||||
}
|
||||
}
|
||||
|
||||
public static class InternalApiAuthExt
|
||||
{
|
||||
public static HttpClient CreateInternalAuthClient(this IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
var httpclient = httpClientFactory.CreateClient(TimeSpan.FromSeconds(10));
|
||||
|
||||
long timestamp = DateTimeHelper.ToUnixTimestamp(DateTime.Now);
|
||||
string randomstr = Guid.NewGuid().ToString();
|
||||
|
||||
var sign = AuthBase.CreateInternalApiSign(timestamp, randomstr);
|
||||
|
||||
httpclient.DefaultRequestHeaders.Add("timestamp", timestamp.ToString());
|
||||
httpclient.DefaultRequestHeaders.Add("randomstr", randomstr);
|
||||
httpclient.DefaultRequestHeaders.Add("internalsign", sign);
|
||||
|
||||
return httpclient;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +1,88 @@
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Core.Web;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi.Filter
|
||||
{
|
||||
public enum LimitDimension
|
||||
{
|
||||
Ip,
|
||||
TenantId,
|
||||
AppId
|
||||
}
|
||||
public class LimitQosAttribute : AuthBase
|
||||
{
|
||||
private int _timeWindow;
|
||||
private int _count;
|
||||
private LimitDimension[] _dimensions;
|
||||
|
||||
public LimitQosAttribute(int timeWindow, int count, params LimitDimension[] dimensions)
|
||||
{
|
||||
_timeWindow = timeWindow;
|
||||
_count = count;
|
||||
_dimensions = dimensions;
|
||||
}
|
||||
|
||||
public override void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
string url = context.HttpContext.Request.Path.ToString().ToLower();
|
||||
|
||||
string cacheKey = $"limitqos:{url}";
|
||||
|
||||
if (_dimensions.Contains(LimitDimension.Ip))
|
||||
{
|
||||
string ip = context.HttpContext.GetUserIp();
|
||||
cacheKey += $":{ip}";
|
||||
}
|
||||
|
||||
if (_dimensions.Contains(LimitDimension.TenantId))
|
||||
{
|
||||
var mangeInfo = context.HttpContext.Request.GetManageUserInfo();
|
||||
|
||||
if (mangeInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cacheKey += $":{mangeInfo.TenantId}";
|
||||
}
|
||||
|
||||
if (_dimensions.Contains(LimitDimension.AppId))
|
||||
{
|
||||
if (!context.HttpContext.Items.ContainsKey("OpenAppId"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cacheKey += $":{context.HttpContext.Items["OpenAppId"]}";
|
||||
}
|
||||
|
||||
var luaScript = $"return redis.call('CL.THROTTLE','{cacheKey}','{_count}','{_count}','{_timeWindow}','1')";
|
||||
|
||||
try
|
||||
{
|
||||
var res = RedisHelper.Eval(luaScript, cacheKey);
|
||||
|
||||
if (res is Array)
|
||||
{
|
||||
var arr = res as Array;
|
||||
|
||||
if (arr.Length == 5)
|
||||
{
|
||||
if (Convert.ToInt32(arr.GetValue(0)) != 0)
|
||||
{
|
||||
context.Reject($"超出{_timeWindow}秒{_count}次的请求限制");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error("reids异常", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Core.Web;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi.Filter
|
||||
{
|
||||
public enum LimitDimension
|
||||
{
|
||||
Ip,
|
||||
TenantId,
|
||||
AppId
|
||||
}
|
||||
public class LimitQosAttribute : AuthBase
|
||||
{
|
||||
private int _timeWindow;
|
||||
private int _count;
|
||||
private LimitDimension[] _dimensions;
|
||||
|
||||
public LimitQosAttribute(int timeWindow, int count, params LimitDimension[] dimensions)
|
||||
{
|
||||
_timeWindow = timeWindow;
|
||||
_count = count;
|
||||
_dimensions = dimensions;
|
||||
}
|
||||
|
||||
public override void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
string url = context.HttpContext.Request.Path.ToString().ToLower();
|
||||
|
||||
string cacheKey = $"limitqos:{url}";
|
||||
|
||||
if (_dimensions.Contains(LimitDimension.Ip))
|
||||
{
|
||||
string ip = context.HttpContext.GetUserIp();
|
||||
cacheKey += $":{ip}";
|
||||
}
|
||||
|
||||
if (_dimensions.Contains(LimitDimension.TenantId))
|
||||
{
|
||||
var mangeInfo = context.HttpContext.Request.GetManageUserInfo();
|
||||
|
||||
if (mangeInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cacheKey += $":{mangeInfo.TenantId}";
|
||||
}
|
||||
|
||||
if (_dimensions.Contains(LimitDimension.AppId))
|
||||
{
|
||||
if (!context.HttpContext.Items.ContainsKey("OpenAppId"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cacheKey += $":{context.HttpContext.Items["OpenAppId"]}";
|
||||
}
|
||||
|
||||
var luaScript = $"return redis.call('CL.THROTTLE','{cacheKey}','{_count}','{_count}','{_timeWindow}','1')";
|
||||
|
||||
try
|
||||
{
|
||||
var res = RedisHelper.Eval(luaScript, cacheKey);
|
||||
|
||||
if (res is Array)
|
||||
{
|
||||
var arr = res as Array;
|
||||
|
||||
if (arr.Length == 5)
|
||||
{
|
||||
if (Convert.ToInt32(arr.GetValue(0)) != 0)
|
||||
{
|
||||
context.Reject($"超出{_timeWindow}秒{_count}次的请求限制");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error("reids异常", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,148 +1,148 @@
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Hncore.Infrastructure.Serializer;
|
||||
using JWT;
|
||||
using JWT.Serializers;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public class ManageAuthAttribute : AuthBase, IOrderedFilter
|
||||
{
|
||||
public int Order =>1;
|
||||
|
||||
public override void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
|
||||
if (context.AllowAnonymous()
|
||||
|| context.HasPassed()
|
||||
|| !context.HasTokenAuthInfo())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.HttpContext.Request.GetManageUserInfo() == null)
|
||||
{
|
||||
context.Reject();
|
||||
}
|
||||
|
||||
context.SetPassed("ManageAuth");
|
||||
}
|
||||
}
|
||||
|
||||
public class ManageUserInfo
|
||||
{
|
||||
[JsonProperty("LoginName")] public string LoginName { get; set; }
|
||||
|
||||
[JsonProperty("RoleName")] public string RoleName { get; set; }
|
||||
|
||||
[JsonProperty("OperaterID")] public int OperaterId { get; set; }
|
||||
|
||||
[JsonProperty("TenantId")] public int TenantId { get; set; }
|
||||
|
||||
[JsonProperty("DataDomain")] public int StoreId { get; set; }
|
||||
|
||||
[JsonProperty("exp")] public long ExpiredTimestamp { get; set; }
|
||||
|
||||
[JsonProperty("iat")] public long IssueTimestamp { get; set; }
|
||||
[JsonProperty("OpenId")] public string OpenId { get; set; }
|
||||
}
|
||||
|
||||
public static class HttpRequestExt
|
||||
{
|
||||
private static string _secret = "etor_yh_lzh_20f_2020_YES";
|
||||
|
||||
public static void SetManageUserInfo(this HttpRequest request, ManageUserInfo manageUserInfo)
|
||||
{
|
||||
request.HttpContext.Items["ManageUserInfo"] = manageUserInfo;
|
||||
}
|
||||
|
||||
public static ManageUserInfo GetManageUserInfo(this HttpRequest request)
|
||||
{
|
||||
if (!request.Headers.ContainsKey("token"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (request.HttpContext.Items.ContainsKey("ManageUserInfo"))
|
||||
{
|
||||
return request.HttpContext.Items["ManageUserInfo"] as ManageUserInfo;
|
||||
}
|
||||
|
||||
string token = request.Headers["token"];
|
||||
|
||||
string storeId = request.Headers["sid"];
|
||||
|
||||
string payload = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
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);
|
||||
payload = decoder.Decode(token, _secret, verify: true);
|
||||
|
||||
if (string.IsNullOrEmpty(payload))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ManageUserInfo manageUserInfo = payload.FromJsonTo<ManageUserInfo>();
|
||||
|
||||
if (manageUserInfo == null || manageUserInfo.TenantId == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (manageUserInfo.IssueTimestamp == 0
|
||||
|| DateTimeHelper.UnixTimeStampToDateTime(manageUserInfo.IssueTimestamp) <
|
||||
DateTime.Now.AddHours(-4))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(storeId.Has())
|
||||
{
|
||||
manageUserInfo.StoreId = Convert.ToInt32(storeId);
|
||||
}
|
||||
|
||||
request.SetManageUserInfo(manageUserInfo);
|
||||
|
||||
return manageUserInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpClient CreateManageAuthHttpClient(this HttpRequest request)
|
||||
{
|
||||
var httpclient = request.HttpContext.RequestServices
|
||||
.GetService<IHttpClientFactory>()
|
||||
.CreateClient(TimeSpan.FromMinutes(1));
|
||||
|
||||
httpclient.DefaultRequestHeaders.Add("token", request.Headers["token"].ToString());
|
||||
httpclient.DefaultRequestHeaders.Add("sid", request.Headers["sid"].ToString());
|
||||
|
||||
return httpclient;
|
||||
}
|
||||
}
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Hncore.Infrastructure.Serializer;
|
||||
using JWT;
|
||||
using JWT.Serializers;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public class ManageAuthAttribute : AuthBase, IOrderedFilter
|
||||
{
|
||||
public int Order =>1;
|
||||
|
||||
public override void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
|
||||
if (context.AllowAnonymous()
|
||||
|| context.HasPassed()
|
||||
|| !context.HasTokenAuthInfo())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.HttpContext.Request.GetManageUserInfo() == null)
|
||||
{
|
||||
context.Reject();
|
||||
}
|
||||
|
||||
context.SetPassed("ManageAuth");
|
||||
}
|
||||
}
|
||||
|
||||
public class ManageUserInfo
|
||||
{
|
||||
[JsonProperty("LoginName")] public string LoginName { get; set; }
|
||||
|
||||
[JsonProperty("RoleName")] public string RoleName { get; set; }
|
||||
|
||||
[JsonProperty("OperaterID")] public int OperaterId { get; set; }
|
||||
|
||||
[JsonProperty("TenantId")] public int TenantId { get; set; }
|
||||
|
||||
[JsonProperty("DataDomain")] public int StoreId { get; set; }
|
||||
|
||||
[JsonProperty("exp")] public long ExpiredTimestamp { get; set; }
|
||||
|
||||
[JsonProperty("iat")] public long IssueTimestamp { get; set; }
|
||||
[JsonProperty("OpenId")] public string OpenId { get; set; }
|
||||
}
|
||||
|
||||
public static class HttpRequestExt
|
||||
{
|
||||
private static string _secret = "etor_yh_lzh_20f_2020_YES";
|
||||
|
||||
public static void SetManageUserInfo(this HttpRequest request, ManageUserInfo manageUserInfo)
|
||||
{
|
||||
request.HttpContext.Items["ManageUserInfo"] = manageUserInfo;
|
||||
}
|
||||
|
||||
public static ManageUserInfo GetManageUserInfo(this HttpRequest request)
|
||||
{
|
||||
if (!request.Headers.ContainsKey("token"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (request.HttpContext.Items.ContainsKey("ManageUserInfo"))
|
||||
{
|
||||
return request.HttpContext.Items["ManageUserInfo"] as ManageUserInfo;
|
||||
}
|
||||
|
||||
string token = request.Headers["token"];
|
||||
|
||||
string storeId = request.Headers["sid"];
|
||||
|
||||
string payload = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
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);
|
||||
payload = decoder.Decode(token, _secret, verify: true);
|
||||
|
||||
if (string.IsNullOrEmpty(payload))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ManageUserInfo manageUserInfo = payload.FromJsonTo<ManageUserInfo>();
|
||||
|
||||
if (manageUserInfo == null || manageUserInfo.TenantId == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (manageUserInfo.IssueTimestamp == 0
|
||||
|| DateTimeHelper.UnixTimeStampToDateTime(manageUserInfo.IssueTimestamp) <
|
||||
DateTime.Now.AddHours(-4))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if(storeId.Has())
|
||||
{
|
||||
manageUserInfo.StoreId = Convert.ToInt32(storeId);
|
||||
}
|
||||
|
||||
request.SetManageUserInfo(manageUserInfo);
|
||||
|
||||
return manageUserInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpClient CreateManageAuthHttpClient(this HttpRequest request)
|
||||
{
|
||||
var httpclient = request.HttpContext.RequestServices
|
||||
.GetService<IHttpClientFactory>()
|
||||
.CreateClient(TimeSpan.FromMinutes(1));
|
||||
|
||||
httpclient.DefaultRequestHeaders.Add("token", request.Headers["token"].ToString());
|
||||
httpclient.DefaultRequestHeaders.Add("sid", request.Headers["sid"].ToString());
|
||||
|
||||
return httpclient;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,166 +1,166 @@
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Hncore.Infrastructure.Serializer;
|
||||
using JWT;
|
||||
using JWT.Serializers;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public class UserAuthAttribute : AuthBase, IOrderedFilter
|
||||
{
|
||||
public int Order => 0;
|
||||
|
||||
public override void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
|
||||
if (context.HasPassed())//context.AllowAnonymous()||
|
||||
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.HttpContext.Request.GetUserInfo() == null)
|
||||
{
|
||||
// context.Reject();
|
||||
context.HttpContext.Response.Cookies.Delete("token");
|
||||
context.HttpContext.Response.Cookies.Delete("userInfo");
|
||||
|
||||
var userAgent = context.HttpContext.Request.Headers[HeaderNames.UserAgent].ToString().ToLower();
|
||||
if (userAgent.IndexOf("micromessenger") == -1)
|
||||
{
|
||||
context.RejectToRedirect("/User/WebLogin");
|
||||
}
|
||||
else
|
||||
{
|
||||
var url = context.HttpContext.Request.GetUrl().UrlEncode();
|
||||
context.RejectToRedirect($"/User/MP_GetUserInfo?appid=wx18e5b4f42773c3ec&callbakUrl={url}");
|
||||
}
|
||||
}
|
||||
|
||||
context.SetPassed("UserAuth");
|
||||
}
|
||||
}
|
||||
|
||||
public class AppUserInfo
|
||||
{
|
||||
[JsonProperty("LoginName")] public string LoginName { get; set; }
|
||||
|
||||
[JsonProperty("Name")] public string Name { get; set; }
|
||||
|
||||
[JsonProperty("RoleName")] public string RoleName { get; set; }
|
||||
|
||||
[JsonProperty("UserId")] public int UserId { get; set; }
|
||||
|
||||
[JsonProperty("TenantId")] public int TenantId { get; set; }
|
||||
|
||||
[JsonProperty("DataDomain")] public int[] DataDomain { get; set; }
|
||||
|
||||
[JsonProperty("exp")] public long ExpiredTimestamp { get; set; }
|
||||
|
||||
[JsonProperty("iat")] public long IssueTimestamp { get; set; }
|
||||
[JsonProperty("OpenId")] public string OpenId { get; set; }
|
||||
[JsonProperty("AppType")] public string AppType { get; set; }
|
||||
[JsonProperty("AppId")] public string AppId { get; set; }
|
||||
[JsonProperty("StoreId")] public int StoreId { get; set; }
|
||||
}
|
||||
|
||||
public static class HttpRequestExt1
|
||||
{
|
||||
private static string _secret = "hncore_yh_lzh_20f_2020_READY";
|
||||
|
||||
public static void SetUserInfo(this HttpRequest request, AppUserInfo manageUserInfo)
|
||||
{
|
||||
request.HttpContext.Items["UserInfo"] = manageUserInfo;
|
||||
}
|
||||
|
||||
public static AppUserInfo GetUserInfo(this HttpRequest request)
|
||||
{
|
||||
if (!request.Headers.ContainsKey("token")&& !request.Cookies.ContainsKey("token"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (request.HttpContext.Items.ContainsKey("UserInfo"))
|
||||
{
|
||||
return request.HttpContext.Items["UserInfo"] as AppUserInfo;
|
||||
}
|
||||
|
||||
if(!request.Cookies.TryGetValue("token",out string token))
|
||||
{
|
||||
token = request.Headers["token"];
|
||||
}
|
||||
string payload = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
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);
|
||||
payload = decoder.Decode(token, _secret, verify: true);
|
||||
|
||||
if (string.IsNullOrEmpty(payload))
|
||||
{
|
||||
request.HttpContext.Response.Cookies.Delete("token");
|
||||
request.HttpContext.Response.Cookies.Delete("userInfo");
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
AppUserInfo manageUserInfo = payload.FromJsonTo<AppUserInfo>();
|
||||
|
||||
if (manageUserInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (manageUserInfo.IssueTimestamp == 0
|
||||
|| DateTimeHelper.UnixTimeStampToDateTime(manageUserInfo.IssueTimestamp) <
|
||||
DateTime.Now.AddHours(-4))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
request.SetUserInfo(manageUserInfo);
|
||||
|
||||
return manageUserInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
request.HttpContext.Response.Cookies.Delete("token");
|
||||
request.HttpContext.Response.Cookies.Delete("userInfo");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
request.HttpContext.Response.Cookies.Delete("token");
|
||||
request.HttpContext.Response.Cookies.Delete("userInfo");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpClient CreateManageAuthHttpClient(this HttpRequest request)
|
||||
{
|
||||
var httpclient = request.HttpContext.RequestServices
|
||||
.GetService<IHttpClientFactory>()
|
||||
.CreateClient(TimeSpan.FromMinutes(1));
|
||||
|
||||
httpclient.DefaultRequestHeaders.Add("token", request.Headers["token"].ToString());
|
||||
|
||||
return httpclient;
|
||||
}
|
||||
}
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Hncore.Infrastructure.Serializer;
|
||||
using JWT;
|
||||
using JWT.Serializers;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public class UserAuthAttribute : AuthBase, IOrderedFilter
|
||||
{
|
||||
public int Order => 0;
|
||||
|
||||
public override void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
|
||||
if (context.HasPassed())//context.AllowAnonymous()||
|
||||
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.HttpContext.Request.GetUserInfo() == null)
|
||||
{
|
||||
// context.Reject();
|
||||
context.HttpContext.Response.Cookies.Delete("token");
|
||||
context.HttpContext.Response.Cookies.Delete("userInfo");
|
||||
|
||||
var userAgent = context.HttpContext.Request.Headers[HeaderNames.UserAgent].ToString().ToLower();
|
||||
if (userAgent.IndexOf("micromessenger") == -1)
|
||||
{
|
||||
context.RejectToRedirect("/User/WebLogin");
|
||||
}
|
||||
else
|
||||
{
|
||||
var url = context.HttpContext.Request.GetUrl().UrlEncode();
|
||||
context.RejectToRedirect($"/User/MP_GetUserInfo?appid=wx18e5b4f42773c3ec&callbakUrl={url}");
|
||||
}
|
||||
}
|
||||
|
||||
context.SetPassed("UserAuth");
|
||||
}
|
||||
}
|
||||
|
||||
public class AppUserInfo
|
||||
{
|
||||
[JsonProperty("LoginName")] public string LoginName { get; set; }
|
||||
|
||||
[JsonProperty("Name")] public string Name { get; set; }
|
||||
|
||||
[JsonProperty("RoleName")] public string RoleName { get; set; }
|
||||
|
||||
[JsonProperty("UserId")] public int UserId { get; set; }
|
||||
|
||||
[JsonProperty("TenantId")] public int TenantId { get; set; }
|
||||
|
||||
[JsonProperty("DataDomain")] public int[] DataDomain { get; set; }
|
||||
|
||||
[JsonProperty("exp")] public long ExpiredTimestamp { get; set; }
|
||||
|
||||
[JsonProperty("iat")] public long IssueTimestamp { get; set; }
|
||||
[JsonProperty("OpenId")] public string OpenId { get; set; }
|
||||
[JsonProperty("AppType")] public string AppType { get; set; }
|
||||
[JsonProperty("AppId")] public string AppId { get; set; }
|
||||
[JsonProperty("StoreId")] public int StoreId { get; set; }
|
||||
}
|
||||
|
||||
public static class HttpRequestExt1
|
||||
{
|
||||
private static string _secret = "hncore_yh_lzh_20f_2020_READY";
|
||||
|
||||
public static void SetUserInfo(this HttpRequest request, AppUserInfo manageUserInfo)
|
||||
{
|
||||
request.HttpContext.Items["UserInfo"] = manageUserInfo;
|
||||
}
|
||||
|
||||
public static AppUserInfo GetUserInfo(this HttpRequest request)
|
||||
{
|
||||
if (!request.Headers.ContainsKey("token")&& !request.Cookies.ContainsKey("token"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (request.HttpContext.Items.ContainsKey("UserInfo"))
|
||||
{
|
||||
return request.HttpContext.Items["UserInfo"] as AppUserInfo;
|
||||
}
|
||||
|
||||
if(!request.Cookies.TryGetValue("token",out string token))
|
||||
{
|
||||
token = request.Headers["token"];
|
||||
}
|
||||
string payload = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
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);
|
||||
payload = decoder.Decode(token, _secret, verify: true);
|
||||
|
||||
if (string.IsNullOrEmpty(payload))
|
||||
{
|
||||
request.HttpContext.Response.Cookies.Delete("token");
|
||||
request.HttpContext.Response.Cookies.Delete("userInfo");
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
AppUserInfo manageUserInfo = payload.FromJsonTo<AppUserInfo>();
|
||||
|
||||
if (manageUserInfo == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (manageUserInfo.IssueTimestamp == 0
|
||||
|| DateTimeHelper.UnixTimeStampToDateTime(manageUserInfo.IssueTimestamp) <
|
||||
DateTime.Now.AddHours(-4))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
request.SetUserInfo(manageUserInfo);
|
||||
|
||||
return manageUserInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
request.HttpContext.Response.Cookies.Delete("token");
|
||||
request.HttpContext.Response.Cookies.Delete("userInfo");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
request.HttpContext.Response.Cookies.Delete("token");
|
||||
request.HttpContext.Response.Cookies.Delete("userInfo");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpClient CreateManageAuthHttpClient(this HttpRequest request)
|
||||
{
|
||||
var httpclient = request.HttpContext.RequestServices
|
||||
.GetService<IHttpClientFactory>()
|
||||
.CreateClient(TimeSpan.FromMinutes(1));
|
||||
|
||||
httpclient.DefaultRequestHeaders.Add("token", request.Headers["token"].ToString());
|
||||
|
||||
return httpclient;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +1,106 @@
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi.Filter
|
||||
{
|
||||
public class SwaggerAddEnumDescriptionsDocumentFilter : IDocumentFilter
|
||||
{
|
||||
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
|
||||
{
|
||||
// add enum descriptions to result models
|
||||
// 将枚举加到返回对象的描述中,json.definitions对象里的枚举
|
||||
foreach (KeyValuePair<string, Schema> schemaDictionaryItem in swaggerDoc.Definitions)
|
||||
{
|
||||
Schema schema = schemaDictionaryItem.Value;
|
||||
foreach (KeyValuePair<string, Schema> propertyDictionaryItem in schema.Properties)
|
||||
{
|
||||
Schema property = propertyDictionaryItem.Value;
|
||||
IList<object> propertyEnums = property.Enum;
|
||||
if (propertyEnums != null && propertyEnums.Count > 0)
|
||||
{
|
||||
property.Description += DescribeEnum(propertyEnums);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add enum descriptions to input parameters
|
||||
if (swaggerDoc.Paths.Count > 0)
|
||||
{
|
||||
foreach (PathItem pathItem in swaggerDoc.Paths.Values)
|
||||
{
|
||||
DescribeEnumParameters(pathItem.Parameters);
|
||||
// head, patch, options, delete left out
|
||||
List<Operation> possibleParameterisedOperations = new List<Operation> { pathItem.Get, pathItem.Post, pathItem.Put };
|
||||
possibleParameterisedOperations.FindAll(x => x != null).ForEach(x => DescribeEnumParameters(x.Parameters));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DescribeEnumParameters(IList<IParameter> parameters)
|
||||
{
|
||||
if (parameters != null)
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
if (param.In == "path")
|
||||
{
|
||||
var nonParam = (NonBodyParameter)param;
|
||||
IList<object> paramEnums = nonParam.Enum;
|
||||
if (paramEnums != null && paramEnums.Count > 0)
|
||||
{
|
||||
param.Description +=":"+ DescribeEnum(paramEnums);
|
||||
}
|
||||
}
|
||||
if (param.In == "body")
|
||||
{
|
||||
var bodyParam = (BodyParameter)param;
|
||||
Schema property = bodyParam.Schema;
|
||||
IList<object> propertyEnums = property.Enum;
|
||||
if (propertyEnums != null && propertyEnums.Count > 0)
|
||||
{
|
||||
property.Description += ":" + DescribeEnum(propertyEnums);
|
||||
}
|
||||
}
|
||||
if (param.In == "query")
|
||||
{
|
||||
var nonParam = (NonBodyParameter)param;
|
||||
IList<object> paramEnums = nonParam.Enum;
|
||||
if (paramEnums != null && paramEnums.Count > 0)
|
||||
{
|
||||
param.Description += ":" + DescribeEnum(paramEnums);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 枚举转换成值和描述
|
||||
/// </summary>
|
||||
/// <param name="enums"></param>
|
||||
/// <returns></returns>
|
||||
private string DescribeEnum(IList<object> enums)
|
||||
{
|
||||
List<string> enumDescriptions = new List<string>();
|
||||
foreach (object item in enums)
|
||||
{
|
||||
var type = item.GetType();
|
||||
var objArr = type.GetField(item.ToString()).GetCustomAttributes(typeof(DisplayAttribute), true);
|
||||
if (objArr != null && objArr.Length > 0)
|
||||
{
|
||||
DisplayAttribute da = objArr[0] as DisplayAttribute;
|
||||
enumDescriptions.Add($"{(int)item} {da.Name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
enumDescriptions.Add(string.Format("{0} = {1}", (int)item, Enum.GetName(item.GetType(), item)));
|
||||
}
|
||||
}
|
||||
return string.Join(", ", enumDescriptions.ToArray());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi.Filter
|
||||
{
|
||||
public class SwaggerAddEnumDescriptionsDocumentFilter : IDocumentFilter
|
||||
{
|
||||
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
|
||||
{
|
||||
// add enum descriptions to result models
|
||||
// 将枚举加到返回对象的描述中,json.definitions对象里的枚举
|
||||
foreach (KeyValuePair<string, Schema> schemaDictionaryItem in swaggerDoc.Definitions)
|
||||
{
|
||||
Schema schema = schemaDictionaryItem.Value;
|
||||
foreach (KeyValuePair<string, Schema> propertyDictionaryItem in schema.Properties)
|
||||
{
|
||||
Schema property = propertyDictionaryItem.Value;
|
||||
IList<object> propertyEnums = property.Enum;
|
||||
if (propertyEnums != null && propertyEnums.Count > 0)
|
||||
{
|
||||
property.Description += DescribeEnum(propertyEnums);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add enum descriptions to input parameters
|
||||
if (swaggerDoc.Paths.Count > 0)
|
||||
{
|
||||
foreach (PathItem pathItem in swaggerDoc.Paths.Values)
|
||||
{
|
||||
DescribeEnumParameters(pathItem.Parameters);
|
||||
// head, patch, options, delete left out
|
||||
List<Operation> possibleParameterisedOperations = new List<Operation> { pathItem.Get, pathItem.Post, pathItem.Put };
|
||||
possibleParameterisedOperations.FindAll(x => x != null).ForEach(x => DescribeEnumParameters(x.Parameters));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DescribeEnumParameters(IList<IParameter> parameters)
|
||||
{
|
||||
if (parameters != null)
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
if (param.In == "path")
|
||||
{
|
||||
var nonParam = (NonBodyParameter)param;
|
||||
IList<object> paramEnums = nonParam.Enum;
|
||||
if (paramEnums != null && paramEnums.Count > 0)
|
||||
{
|
||||
param.Description +=":"+ DescribeEnum(paramEnums);
|
||||
}
|
||||
}
|
||||
if (param.In == "body")
|
||||
{
|
||||
var bodyParam = (BodyParameter)param;
|
||||
Schema property = bodyParam.Schema;
|
||||
IList<object> propertyEnums = property.Enum;
|
||||
if (propertyEnums != null && propertyEnums.Count > 0)
|
||||
{
|
||||
property.Description += ":" + DescribeEnum(propertyEnums);
|
||||
}
|
||||
}
|
||||
if (param.In == "query")
|
||||
{
|
||||
var nonParam = (NonBodyParameter)param;
|
||||
IList<object> paramEnums = nonParam.Enum;
|
||||
if (paramEnums != null && paramEnums.Count > 0)
|
||||
{
|
||||
param.Description += ":" + DescribeEnum(paramEnums);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 枚举转换成值和描述
|
||||
/// </summary>
|
||||
/// <param name="enums"></param>
|
||||
/// <returns></returns>
|
||||
private string DescribeEnum(IList<object> enums)
|
||||
{
|
||||
List<string> enumDescriptions = new List<string>();
|
||||
foreach (object item in enums)
|
||||
{
|
||||
var type = item.GetType();
|
||||
var objArr = type.GetField(item.ToString()).GetCustomAttributes(typeof(DisplayAttribute), true);
|
||||
if (objArr != null && objArr.Length > 0)
|
||||
{
|
||||
DisplayAttribute da = objArr[0] as DisplayAttribute;
|
||||
enumDescriptions.Add($"{(int)item} {da.Name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
enumDescriptions.Add(string.Format("{0} = {1}", (int)item, Enum.GetName(item.GetType(), item)));
|
||||
}
|
||||
}
|
||||
return string.Join(", ", enumDescriptions.ToArray());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
using Microsoft.AspNetCore.JsonPatch.Operations;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi.Filter
|
||||
{
|
||||
public class SwaggerOperationFilter : IOperationFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用过滤器
|
||||
/// </summary>
|
||||
/// <param name="operation"></param>
|
||||
/// <param name="context"></param>
|
||||
public void Apply(Swashbuckle.AspNetCore.Swagger.Operation operation, OperationFilterContext context)
|
||||
{
|
||||
#region Swagger版本描述处理
|
||||
|
||||
foreach (var parameter in operation.Parameters.OfType<NonBodyParameter>())
|
||||
{
|
||||
//var description = context.ApiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
|
||||
if (parameter.Name == "version")
|
||||
{
|
||||
parameter.Description = "填写版本号如:1、2";
|
||||
parameter.Default = context.ApiDescription.GroupName.Replace("v", "");
|
||||
}
|
||||
|
||||
//if (parameter.Enum!=null&¶meter.Enum.Count > 0)
|
||||
//{
|
||||
// string desc = "";
|
||||
// foreach(var item in parameter.Enum)
|
||||
// {
|
||||
// var type = item.GetType();
|
||||
// var objArr=type.GetField(item.ToString()).GetCustomAttributes(typeof(DisplayAttribute), true);
|
||||
// if (objArr != null && objArr.Length > 0)
|
||||
// {
|
||||
// DisplayAttribute da = objArr[0] as DisplayAttribute;
|
||||
// desc += $"{item} {da.Name}";
|
||||
// }
|
||||
// }
|
||||
// parameter.Description = desc;
|
||||
//}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
var auth = context.MethodInfo
|
||||
.GetCustomAttributes(true)
|
||||
.OfType<ManageAuthAttribute>();
|
||||
}
|
||||
}
|
||||
using Microsoft.AspNetCore.JsonPatch.Operations;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi.Filter
|
||||
{
|
||||
public class SwaggerOperationFilter : IOperationFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用过滤器
|
||||
/// </summary>
|
||||
/// <param name="operation"></param>
|
||||
/// <param name="context"></param>
|
||||
public void Apply(Swashbuckle.AspNetCore.Swagger.Operation operation, OperationFilterContext context)
|
||||
{
|
||||
#region Swagger版本描述处理
|
||||
|
||||
foreach (var parameter in operation.Parameters.OfType<NonBodyParameter>())
|
||||
{
|
||||
//var description = context.ApiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
|
||||
if (parameter.Name == "version")
|
||||
{
|
||||
parameter.Description = "填写版本号如:1、2";
|
||||
parameter.Default = context.ApiDescription.GroupName.Replace("v", "");
|
||||
}
|
||||
|
||||
//if (parameter.Enum!=null&¶meter.Enum.Count > 0)
|
||||
//{
|
||||
// string desc = "";
|
||||
// foreach(var item in parameter.Enum)
|
||||
// {
|
||||
// var type = item.GetType();
|
||||
// var objArr=type.GetField(item.ToString()).GetCustomAttributes(typeof(DisplayAttribute), true);
|
||||
// if (objArr != null && objArr.Length > 0)
|
||||
// {
|
||||
// DisplayAttribute da = objArr[0] as DisplayAttribute;
|
||||
// desc += $"{item} {da.Name}";
|
||||
// }
|
||||
// }
|
||||
// parameter.Description = desc;
|
||||
//}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
var auth = context.MethodInfo
|
||||
.GetCustomAttributes(true)
|
||||
.OfType<ManageAuthAttribute>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,46 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi.Filter
|
||||
{
|
||||
public class ValidateModelAttribute : ActionFilterAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// netcore 会自动判断context.ModelState.IsValid
|
||||
/// 如果是false,自动返回BadRequestObjectResult
|
||||
/// 需要在OnResultExecuting重写返回值
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
//var httpContext = context.HttpContext;
|
||||
//if (context.ModelState.IsValid == false)
|
||||
//{
|
||||
// context.Result = new JsonResult(context.ModelState);
|
||||
// //httpContext.Response = httpContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, context.ModelState);
|
||||
//}
|
||||
}
|
||||
public override void OnResultExecuting(ResultExecutingContext context)
|
||||
{
|
||||
var httpContext = context.HttpContext;
|
||||
if (context.ModelState.IsValid == false)
|
||||
{
|
||||
var message = new List<string>(); ;
|
||||
foreach(var item in context.ModelState.Values)
|
||||
{
|
||||
foreach (var error in item.Errors)
|
||||
{
|
||||
message.Add( error.ErrorMessage );
|
||||
}
|
||||
}
|
||||
var apiRes = new ApiResult(ResultCode.C_PARAM_ERROR, string.Join("|", message));
|
||||
context.Result = new JsonResult(apiRes);
|
||||
//httpContext.Response = httpContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, context.ModelState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi.Filter
|
||||
{
|
||||
public class ValidateModelAttribute : ActionFilterAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// netcore 会自动判断context.ModelState.IsValid
|
||||
/// 如果是false,自动返回BadRequestObjectResult
|
||||
/// 需要在OnResultExecuting重写返回值
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
//var httpContext = context.HttpContext;
|
||||
//if (context.ModelState.IsValid == false)
|
||||
//{
|
||||
// context.Result = new JsonResult(context.ModelState);
|
||||
// //httpContext.Response = httpContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, context.ModelState);
|
||||
//}
|
||||
}
|
||||
public override void OnResultExecuting(ResultExecutingContext context)
|
||||
{
|
||||
var httpContext = context.HttpContext;
|
||||
if (context.ModelState.IsValid == false)
|
||||
{
|
||||
var message = new List<string>(); ;
|
||||
foreach(var item in context.ModelState.Values)
|
||||
{
|
||||
foreach (var error in item.Errors)
|
||||
{
|
||||
message.Add( error.ErrorMessage );
|
||||
}
|
||||
}
|
||||
var apiRes = new ApiResult(ResultCode.C_PARAM_ERROR, string.Join("|", message));
|
||||
context.Result = new JsonResult(apiRes);
|
||||
//httpContext.Response = httpContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, context.ModelState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
internal class GlobalData
|
||||
{
|
||||
public static bool UseGlobalManageAuthFilter { get; set; }
|
||||
}
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
internal class GlobalData
|
||||
{
|
||||
public static bool UseGlobalManageAuthFilter { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,103 +1,103 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Data;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Hncore.Infrastructure.OpenApi;
|
||||
using Hncore.Infrastructure.Serializer;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Hncore.Infrastructure.Core.Web;
|
||||
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 统一错误异常处理中间件类
|
||||
/// </summary>
|
||||
///
|
||||
public class ErrorHandlingMiddleware
|
||||
{
|
||||
private readonly RequestDelegate next;
|
||||
|
||||
public ErrorHandlingMiddleware(RequestDelegate next)
|
||||
{
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await next(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string requestMsg = "请求URL:" + context.Request.GetAbsoluteUri() + "";
|
||||
|
||||
requestMsg += "\nMethod:" + context.Request.Method + "\n";
|
||||
|
||||
if (context.Request.Method.ToLower() != "get")
|
||||
{
|
||||
var requestBody = await context.Request.ReadBodyAsStringAsync();
|
||||
requestMsg += "Body:\n" + requestBody +
|
||||
"\n------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
requestMsg += "\n------------------------\n";
|
||||
}
|
||||
|
||||
|
||||
await HandleExceptionAsync(context, ex, requestMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Task HandleExceptionAsync(HttpContext context, Exception ex,
|
||||
string requestMsg)
|
||||
{
|
||||
ResultCode code = ResultCode.C_UNKNOWN_ERROR;
|
||||
string msg = "";
|
||||
|
||||
if (ex is BusinessException bex)
|
||||
{
|
||||
code = bex.Code;
|
||||
msg = bex.Message;
|
||||
|
||||
LogHelper.Error($"业务异常,{msg}", requestMsg + ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (EnvironmentVariableHelper.IsAspNetCoreProduction)
|
||||
{
|
||||
msg = "系统繁忙,请稍后再试";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = ex.Message;
|
||||
}
|
||||
|
||||
LogHelper.Error($"未知异常,{ex.Message}", requestMsg + ex);
|
||||
}
|
||||
|
||||
var data = new ApiResult(code, msg);
|
||||
|
||||
var result = data.ToJson();
|
||||
|
||||
context.Response.ContentType = "application/json;charset=utf-8";
|
||||
|
||||
return context.Response.WriteAsync(result);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ErrorHandlingExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseErrorHandling(this IApplicationBuilder builder)
|
||||
{
|
||||
return builder.UseMiddleware<ErrorHandlingMiddleware>();
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Data;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Hncore.Infrastructure.OpenApi;
|
||||
using Hncore.Infrastructure.Serializer;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Hncore.Infrastructure.Core.Web;
|
||||
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 统一错误异常处理中间件类
|
||||
/// </summary>
|
||||
///
|
||||
public class ErrorHandlingMiddleware
|
||||
{
|
||||
private readonly RequestDelegate next;
|
||||
|
||||
public ErrorHandlingMiddleware(RequestDelegate next)
|
||||
{
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await next(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string requestMsg = "请求URL:" + context.Request.GetAbsoluteUri() + "";
|
||||
|
||||
requestMsg += "\nMethod:" + context.Request.Method + "\n";
|
||||
|
||||
if (context.Request.Method.ToLower() != "get")
|
||||
{
|
||||
var requestBody = await context.Request.ReadBodyAsStringAsync();
|
||||
requestMsg += "Body:\n" + requestBody +
|
||||
"\n------------------------\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
requestMsg += "\n------------------------\n";
|
||||
}
|
||||
|
||||
|
||||
await HandleExceptionAsync(context, ex, requestMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Task HandleExceptionAsync(HttpContext context, Exception ex,
|
||||
string requestMsg)
|
||||
{
|
||||
ResultCode code = ResultCode.C_UNKNOWN_ERROR;
|
||||
string msg = "";
|
||||
|
||||
if (ex is BusinessException bex)
|
||||
{
|
||||
code = bex.Code;
|
||||
msg = bex.Message;
|
||||
|
||||
LogHelper.Error($"业务异常,{msg}", requestMsg + ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (EnvironmentVariableHelper.IsAspNetCoreProduction)
|
||||
{
|
||||
msg = "系统繁忙,请稍后再试";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = ex.Message;
|
||||
}
|
||||
|
||||
LogHelper.Error($"未知异常,{ex.Message}", requestMsg + ex);
|
||||
}
|
||||
|
||||
var data = new ApiResult(code, msg);
|
||||
|
||||
var result = data.ToJson();
|
||||
|
||||
context.Response.ContentType = "application/json;charset=utf-8";
|
||||
|
||||
return context.Response.WriteAsync(result);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ErrorHandlingExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseErrorHandling(this IApplicationBuilder builder)
|
||||
{
|
||||
return builder.UseMiddleware<ErrorHandlingMiddleware>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,76 +1,76 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Common.DingTalk;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NLog.Extensions.Logging;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用程序构建器扩展类
|
||||
/// </summary>
|
||||
///
|
||||
public static class ApplicationBuilderExtend
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化应用程序构建器
|
||||
/// </summary>
|
||||
/// <param name="app">当前应用程序构建器对象</param>
|
||||
/// <param name="loggerFactory">日志工厂对象</param>
|
||||
/// <returns>初始化后的应用程序构建器对象</returns>
|
||||
/// <param name="applicationLifetime">应用程序生命周期对象</param>
|
||||
///
|
||||
public static IApplicationBuilder Init(this IApplicationBuilder app, ILoggerFactory loggerFactory,
|
||||
IApplicationLifetime applicationLifetime)
|
||||
{
|
||||
loggerFactory.AddNLog(); //启用Nlog日志插件
|
||||
|
||||
app.UseErrorHandling(); //添加统一错误异常处理中间件(一个自定义类)
|
||||
|
||||
|
||||
|
||||
//启用Cors(跨域请求)支持(默认关闭状态)
|
||||
|
||||
app.UseCors(builder => builder
|
||||
.SetIsOriginAllowed(host => true) //允许所有来源
|
||||
.AllowAnyMethod() //允许任何请求方法(GET、POST、PUT、DELETE等)
|
||||
.AllowAnyHeader() //允许任何请求头信息
|
||||
.AllowCredentials() //允许跨域凭据
|
||||
// .SetPreflightMaxAge(TimeSpan.FromDays(30)) //指定可以缓存预检请求的响应的时间为30天
|
||||
.WithExposedHeaders("X-Suggested-Filename", "set-user-token", "set-user")
|
||||
);
|
||||
app.UseMvc(); //启用MVC
|
||||
|
||||
|
||||
//向应用程序生命周期的“应用程序已完全启动”事件注册回调函数
|
||||
applicationLifetime.ApplicationStarted.Register(OnAppStarted);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序完全启动完成处理回调函数
|
||||
/// </summary>
|
||||
///
|
||||
private static void OnAppStarted()
|
||||
{
|
||||
//if (EnvironmentVariableHelper.IsAspNetCoreProduction)
|
||||
//{
|
||||
// DingTalkHelper.SendMessage(new MarkDownModel()
|
||||
// {
|
||||
// markdown = new markdown()
|
||||
// {
|
||||
// title = "应用已启动",
|
||||
// text = "### 应用已启动\n\nhostname:" + EnvironmentVariableHelper.HostName + "\n\n" +
|
||||
// DateTime.Now.Format("yyyy-MM-dd HH:mm:ss")
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Hncore.Infrastructure.Common;
|
||||
using Hncore.Infrastructure.Common.DingTalk;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NLog.Extensions.Logging;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用程序构建器扩展类
|
||||
/// </summary>
|
||||
///
|
||||
public static class ApplicationBuilderExtend
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化应用程序构建器
|
||||
/// </summary>
|
||||
/// <param name="app">当前应用程序构建器对象</param>
|
||||
/// <param name="loggerFactory">日志工厂对象</param>
|
||||
/// <returns>初始化后的应用程序构建器对象</returns>
|
||||
/// <param name="applicationLifetime">应用程序生命周期对象</param>
|
||||
///
|
||||
public static IApplicationBuilder Init(this IApplicationBuilder app, ILoggerFactory loggerFactory,
|
||||
IApplicationLifetime applicationLifetime)
|
||||
{
|
||||
loggerFactory.AddNLog(); //启用Nlog日志插件
|
||||
|
||||
app.UseErrorHandling(); //添加统一错误异常处理中间件(一个自定义类)
|
||||
|
||||
|
||||
|
||||
//启用Cors(跨域请求)支持(默认关闭状态)
|
||||
|
||||
app.UseCors(builder => builder
|
||||
.SetIsOriginAllowed(host => true) //允许所有来源
|
||||
.AllowAnyMethod() //允许任何请求方法(GET、POST、PUT、DELETE等)
|
||||
.AllowAnyHeader() //允许任何请求头信息
|
||||
.AllowCredentials() //允许跨域凭据
|
||||
// .SetPreflightMaxAge(TimeSpan.FromDays(30)) //指定可以缓存预检请求的响应的时间为30天
|
||||
.WithExposedHeaders("X-Suggested-Filename", "set-user-token", "set-user")
|
||||
);
|
||||
app.UseMvc(); //启用MVC
|
||||
|
||||
|
||||
//向应用程序生命周期的“应用程序已完全启动”事件注册回调函数
|
||||
applicationLifetime.ApplicationStarted.Register(OnAppStarted);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序完全启动完成处理回调函数
|
||||
/// </summary>
|
||||
///
|
||||
private static void OnAppStarted()
|
||||
{
|
||||
//if (EnvironmentVariableHelper.IsAspNetCoreProduction)
|
||||
//{
|
||||
// DingTalkHelper.SendMessage(new MarkDownModel()
|
||||
// {
|
||||
// markdown = new markdown()
|
||||
// {
|
||||
// title = "应用已启动",
|
||||
// text = "### 应用已启动\n\nhostname:" + EnvironmentVariableHelper.HostName + "\n\n" +
|
||||
// DateTime.Now.Format("yyyy-MM-dd HH:mm:ss")
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,42 @@
|
||||
using System;
|
||||
using System.Runtime;
|
||||
using Hncore.Infrastructure.Serializer;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public static class HostingEnvironmentExtend
|
||||
{
|
||||
public static IConfigurationRoot UseAppsettings(this IHostingEnvironment env)
|
||||
{
|
||||
Console.WriteLine("环境:" + Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));
|
||||
#if DEBUG
|
||||
Console.WriteLine("模式:DEBUG");
|
||||
#endif
|
||||
|
||||
#if RELEASE
|
||||
Console.WriteLine("模式:RELEASE");
|
||||
#endif
|
||||
|
||||
Console.WriteLine("GC模式:" + new
|
||||
{
|
||||
IsServerGC = GCSettings.IsServerGC,
|
||||
LargeObjectHeapCompactionMode = GCSettings.LargeObjectHeapCompactionMode.ToString(),
|
||||
LatencyMode = GCSettings.LatencyMode.ToString()
|
||||
}.ToJson(true));
|
||||
|
||||
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
|
||||
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(env.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
|
||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false)
|
||||
.AddEnvironmentVariables();
|
||||
|
||||
var config = builder.Build();
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Runtime;
|
||||
using Hncore.Infrastructure.Serializer;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
public static class HostingEnvironmentExtend
|
||||
{
|
||||
public static IConfigurationRoot UseAppsettings(this IHostingEnvironment env)
|
||||
{
|
||||
Console.WriteLine("环境:" + Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));
|
||||
#if DEBUG
|
||||
Console.WriteLine("模式:DEBUG");
|
||||
#endif
|
||||
|
||||
#if RELEASE
|
||||
Console.WriteLine("模式:RELEASE");
|
||||
#endif
|
||||
|
||||
Console.WriteLine("GC模式:" + new
|
||||
{
|
||||
IsServerGC = GCSettings.IsServerGC,
|
||||
LargeObjectHeapCompactionMode = GCSettings.LargeObjectHeapCompactionMode.ToString(),
|
||||
LatencyMode = GCSettings.LatencyMode.ToString()
|
||||
}.ToJson(true));
|
||||
|
||||
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
|
||||
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(env.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
|
||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false)
|
||||
.AddEnvironmentVariables();
|
||||
|
||||
var config = builder.Build();
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,113 +1,113 @@
|
||||
using System;
|
||||
using Hncore.Infrastructure.Autofac;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务集合对象(可以理解为内置的依赖注入容器)功能扩展类
|
||||
/// </summary>
|
||||
///
|
||||
public static class ServiceCollectionExtend
|
||||
{
|
||||
/// <summary>
|
||||
/// 通用初始化方法(被各个微服务项目所引用)
|
||||
/// </summary>
|
||||
/// <param name="services">服务集合对象</param>
|
||||
/// <param name="configuration">配置信息对象</param>
|
||||
/// <param name="version">.net core兼容版本</param>
|
||||
/// <param name="serviceOption">服务自定义选项对象</param>
|
||||
/// <returns>服务提供者对象</returns>
|
||||
///
|
||||
public static IServiceProvider Init(this IServiceCollection services, IConfiguration configuration,
|
||||
CompatibilityVersion version, ServiceOption serviceOption = null)
|
||||
{
|
||||
//启用选项配置服务
|
||||
services.AddOptions();
|
||||
|
||||
//将配置信息对象以单例模式添加到服务集合中
|
||||
services.AddSingleton(configuration);
|
||||
|
||||
// services.AddCors();
|
||||
var mvcbuilder = services
|
||||
.AddMvc(options =>
|
||||
{
|
||||
options.EnableEndpointRouting = false; //关闭终端点路由
|
||||
|
||||
if (serviceOption != null && serviceOption.UseGlobalManageAuthFilter)
|
||||
{
|
||||
//如果配置并传递了自定义选项中的全局授权过滤器,就将全局授权过滤器添加到MVC全局过滤器链中让其生效
|
||||
options.Filters.Add(new ManageAuthAttribute());
|
||||
|
||||
GlobalData.UseGlobalManageAuthFilter = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
GlobalData.UseGlobalManageAuthFilter = false;
|
||||
}
|
||||
})
|
||||
.SetCompatibilityVersion(version) //设置.net core兼容版本号
|
||||
.AddJsonOptions(options =>
|
||||
{
|
||||
//使用NewtonsoftJson插件,替换掉系统默认提供的JSON插件
|
||||
options.SerializerSettings.ContractResolver =
|
||||
new Newtonsoft.Json.Serialization.DefaultContractResolver();
|
||||
|
||||
//定义日期格式化策略
|
||||
options.SerializerSettings.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
|
||||
|
||||
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
|
||||
|
||||
//定义循环引用处理策略(就是要序列化的对象类A中引用了B,B引用了C……转了一圈儿之后又直接或间接引用回了A,就称为循环引用)
|
||||
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||
|
||||
//序列化或反序列化时,可接受的日期时间字符串格式
|
||||
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
if (serviceOption != null && serviceOption.IgnoreJsonNullValue)
|
||||
{
|
||||
//如果配置并传递了自定义选项中的忽略空值选项,就在操作JSON时忽略掉空值数据
|
||||
//忽略掉空值的意思就是如果对象中的某个属性值为null,它将不会出现在最终序列化后的JSON字符串中
|
||||
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
|
||||
}
|
||||
});
|
||||
|
||||
services.AddApiVersioning(option =>
|
||||
{
|
||||
//设置API版本信息
|
||||
option.ReportApiVersions = true; //在向客户端响应的响应头中显示受支持的API版本信息
|
||||
option.AssumeDefaultVersionWhenUnspecified = true; //如果客户端未提供并指定要调用的API版本,就以下方的默认版本为准
|
||||
option.DefaultApiVersion = new ApiVersion(1, 0); //默认版本号
|
||||
});
|
||||
|
||||
//启用HTTP请求上下文访问器(用来访问类似传统MVC中的那个HttpContext对象)
|
||||
services.AddHttpContextAccessor();
|
||||
|
||||
|
||||
|
||||
|
||||
//构建并返回服务提供对象(在Build方法中主要用Autofac插件替换掉了默认的依赖注入插件,并做一些自动扫描配置)
|
||||
return new MvcAutoRegister().Build(services, mvcbuilder);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务自定义配置类(承载一些自定义配置)
|
||||
/// </summary>
|
||||
///
|
||||
public class ServiceOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否启用全局授权过滤器(默认关闭)
|
||||
/// </summary>
|
||||
public bool UseGlobalManageAuthFilter { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否在生成的JSON字符串中忽略掉为null的属性或字段(默认为false,意思就是就算字段为null也会出现在最终序列化后的JSON字符串中)
|
||||
/// </summary>
|
||||
public bool IgnoreJsonNullValue { get; set; } = false;
|
||||
}
|
||||
using System;
|
||||
using Hncore.Infrastructure.Autofac;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Hncore.Infrastructure.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务集合对象(可以理解为内置的依赖注入容器)功能扩展类
|
||||
/// </summary>
|
||||
///
|
||||
public static class ServiceCollectionExtend
|
||||
{
|
||||
/// <summary>
|
||||
/// 通用初始化方法(被各个微服务项目所引用)
|
||||
/// </summary>
|
||||
/// <param name="services">服务集合对象</param>
|
||||
/// <param name="configuration">配置信息对象</param>
|
||||
/// <param name="version">.net core兼容版本</param>
|
||||
/// <param name="serviceOption">服务自定义选项对象</param>
|
||||
/// <returns>服务提供者对象</returns>
|
||||
///
|
||||
public static IServiceProvider Init(this IServiceCollection services, IConfiguration configuration,
|
||||
CompatibilityVersion version, ServiceOption serviceOption = null)
|
||||
{
|
||||
//启用选项配置服务
|
||||
services.AddOptions();
|
||||
|
||||
//将配置信息对象以单例模式添加到服务集合中
|
||||
services.AddSingleton(configuration);
|
||||
|
||||
// services.AddCors();
|
||||
var mvcbuilder = services
|
||||
.AddMvc(options =>
|
||||
{
|
||||
options.EnableEndpointRouting = false; //关闭终端点路由
|
||||
|
||||
if (serviceOption != null && serviceOption.UseGlobalManageAuthFilter)
|
||||
{
|
||||
//如果配置并传递了自定义选项中的全局授权过滤器,就将全局授权过滤器添加到MVC全局过滤器链中让其生效
|
||||
options.Filters.Add(new ManageAuthAttribute());
|
||||
|
||||
GlobalData.UseGlobalManageAuthFilter = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
GlobalData.UseGlobalManageAuthFilter = false;
|
||||
}
|
||||
})
|
||||
.SetCompatibilityVersion(version) //设置.net core兼容版本号
|
||||
.AddJsonOptions(options =>
|
||||
{
|
||||
//使用NewtonsoftJson插件,替换掉系统默认提供的JSON插件
|
||||
options.SerializerSettings.ContractResolver =
|
||||
new Newtonsoft.Json.Serialization.DefaultContractResolver();
|
||||
|
||||
//定义日期格式化策略
|
||||
options.SerializerSettings.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
|
||||
|
||||
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
|
||||
|
||||
//定义循环引用处理策略(就是要序列化的对象类A中引用了B,B引用了C……转了一圈儿之后又直接或间接引用回了A,就称为循环引用)
|
||||
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||
|
||||
//序列化或反序列化时,可接受的日期时间字符串格式
|
||||
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
if (serviceOption != null && serviceOption.IgnoreJsonNullValue)
|
||||
{
|
||||
//如果配置并传递了自定义选项中的忽略空值选项,就在操作JSON时忽略掉空值数据
|
||||
//忽略掉空值的意思就是如果对象中的某个属性值为null,它将不会出现在最终序列化后的JSON字符串中
|
||||
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
|
||||
}
|
||||
});
|
||||
|
||||
services.AddApiVersioning(option =>
|
||||
{
|
||||
//设置API版本信息
|
||||
option.ReportApiVersions = true; //在向客户端响应的响应头中显示受支持的API版本信息
|
||||
option.AssumeDefaultVersionWhenUnspecified = true; //如果客户端未提供并指定要调用的API版本,就以下方的默认版本为准
|
||||
option.DefaultApiVersion = new ApiVersion(1, 0); //默认版本号
|
||||
});
|
||||
|
||||
//启用HTTP请求上下文访问器(用来访问类似传统MVC中的那个HttpContext对象)
|
||||
services.AddHttpContextAccessor();
|
||||
|
||||
|
||||
|
||||
|
||||
//构建并返回服务提供对象(在Build方法中主要用Autofac插件替换掉了默认的依赖注入插件,并做一些自动扫描配置)
|
||||
return new MvcAutoRegister().Build(services, mvcbuilder);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务自定义配置类(承载一些自定义配置)
|
||||
/// </summary>
|
||||
///
|
||||
public class ServiceOption
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否启用全局授权过滤器(默认关闭)
|
||||
/// </summary>
|
||||
public bool UseGlobalManageAuthFilter { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否在生成的JSON字符串中忽略掉为null的属性或字段(默认为false,意思就是就算字段为null也会出现在最终序列化后的JSON字符串中)
|
||||
/// </summary>
|
||||
public bool IgnoreJsonNullValue { get; set; } = false;
|
||||
}
|
||||
}
|
||||
@@ -1,71 +1,71 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hncore.Infrastructure.Core.Web
|
||||
{
|
||||
public static class HttpContextExtension
|
||||
{
|
||||
public static string GetUserIp(this HttpContext context)
|
||||
{
|
||||
var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = context.Connection.RemoteIpAddress.ToString();
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
public static string GetAbsoluteUri(this HttpRequest request)
|
||||
{
|
||||
return new StringBuilder()
|
||||
.Append(request.Scheme)
|
||||
.Append("://")
|
||||
.Append(request.Host)
|
||||
.Append(request.PathBase)
|
||||
.Append(request.Path)
|
||||
.Append(request.QueryString)
|
||||
.ToString();
|
||||
}
|
||||
|
||||
public static async Task<string> ReadBodyAsStringAsync(this HttpRequest request)
|
||||
{
|
||||
request.EnableBuffering();
|
||||
|
||||
var requestReader = new StreamReader(request.Body);
|
||||
|
||||
var requestBody = await requestReader.ReadToEndAsync();
|
||||
|
||||
request.Body.Position = 0;
|
||||
|
||||
return requestBody;
|
||||
}
|
||||
}
|
||||
|
||||
public static class IsLocalExtension
|
||||
{
|
||||
private const string NullIpAddress = "::1";
|
||||
|
||||
public static bool IsLocal(this HttpRequest req)
|
||||
{
|
||||
var connection = req.HttpContext.Connection;
|
||||
if (connection.RemoteIpAddress.IsSet())
|
||||
{
|
||||
return connection.LocalIpAddress.IsSet()
|
||||
? connection.RemoteIpAddress.Equals(connection.LocalIpAddress)
|
||||
: IPAddress.IsLoopback(connection.RemoteIpAddress);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsSet(this IPAddress address)
|
||||
{
|
||||
return address != null && address.ToString() != NullIpAddress;
|
||||
}
|
||||
}
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hncore.Infrastructure.Core.Web
|
||||
{
|
||||
public static class HttpContextExtension
|
||||
{
|
||||
public static string GetUserIp(this HttpContext context)
|
||||
{
|
||||
var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = context.Connection.RemoteIpAddress.ToString();
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
public static string GetAbsoluteUri(this HttpRequest request)
|
||||
{
|
||||
return new StringBuilder()
|
||||
.Append(request.Scheme)
|
||||
.Append("://")
|
||||
.Append(request.Host)
|
||||
.Append(request.PathBase)
|
||||
.Append(request.Path)
|
||||
.Append(request.QueryString)
|
||||
.ToString();
|
||||
}
|
||||
|
||||
public static async Task<string> ReadBodyAsStringAsync(this HttpRequest request)
|
||||
{
|
||||
request.EnableBuffering();
|
||||
|
||||
var requestReader = new StreamReader(request.Body);
|
||||
|
||||
var requestBody = await requestReader.ReadToEndAsync();
|
||||
|
||||
request.Body.Position = 0;
|
||||
|
||||
return requestBody;
|
||||
}
|
||||
}
|
||||
|
||||
public static class IsLocalExtension
|
||||
{
|
||||
private const string NullIpAddress = "::1";
|
||||
|
||||
public static bool IsLocal(this HttpRequest req)
|
||||
{
|
||||
var connection = req.HttpContext.Connection;
|
||||
if (connection.RemoteIpAddress.IsSet())
|
||||
{
|
||||
return connection.LocalIpAddress.IsSet()
|
||||
? connection.RemoteIpAddress.Equals(connection.LocalIpAddress)
|
||||
: IPAddress.IsLoopback(connection.RemoteIpAddress);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsSet(this IPAddress address)
|
||||
{
|
||||
return address != null && address.ToString() != NullIpAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user