shengxuefei пре 4 година
родитељ
комит
c49aae7268

+ 43 - 0
WebAPIBase.NetCore/Utils/Jwt/ITokenHelper.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WebAPIBase.Utils.Jwt
+{
+    /// <summary>
+    /// token工具类的接口,方便使用依赖注入
+    /// </summary>
+    public interface ITokenHelper
+    {
+        /// <summary>
+        /// 根据一个对象通过反射提供负载生成token
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="user"></param>
+        /// <returns></returns>
+        TnToken CreateToken<T>(T user) where T : class;
+        /// <summary>
+        /// 根据键值对提供负载生成token
+        /// </summary>
+        /// <param name="keyValuePairs"></param>
+        /// <returns></returns>
+        TnToken CreateToken(Dictionary<string, string> keyValuePairs);
+        /// <summary>
+        /// Token验证
+        /// </summary>
+        /// <param name="encodeJwt">token</param>
+        /// <param name="validatePayLoad">自定义各类验证; 是否包含那种申明,或者申明的值</param>
+        /// <returns></returns>
+        bool ValiToken(string encodeJwt, Func<Dictionary<string, string>, bool> validatePayLoad = null);
+        /// <summary>
+        /// 带返回状态的Token验证
+        /// </summary>
+        /// <param name="encodeJwt">token</param>
+        /// <param name="validatePayLoad">自定义各类验证; 是否包含那种申明,或者申明的值</param>
+        /// <param name="action"></param>
+        /// <returns></returns>
+        TokenType ValiTokenState(string encodeJwt, Func<Dictionary<string, string>, bool> validatePayLoad, Action<Dictionary<string, string>> action);
+    }
+}

+ 31 - 0
WebAPIBase.NetCore/Utils/Jwt/JWTConfig.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WebAPIBase.Utils.Jwt
+{
+    /// <summary>
+    /// 配置token生成信息
+    /// </summary>
+    public class JWTConfig
+    {
+        /// <summary>
+        /// Token发布者
+        /// </summary>
+        public string Issuer { get; set; }
+        /// <summary>
+        /// Token接受者
+        /// </summary>
+        public string Audience { get; set; }
+        /// <summary>
+        /// 秘钥
+        /// </summary>
+        public string IssuerSigningKey { get; set; }
+        /// <summary>
+        /// 过期时间
+        /// </summary>
+        public int AccessTokenExpiresMinutes { get; set; }
+    }
+}

+ 23 - 0
WebAPIBase.NetCore/Utils/Jwt/TnToken.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WebAPIBase.Utils.Jwt
+{
+    /// <summary>
+    /// 存放Token 跟过期时间的类
+    /// </summary>
+    public class TnToken
+    {
+        /// <summary>
+        /// token令牌
+        /// </summary>
+        public string TokenStr { get; set; }
+        /// <summary>
+        /// 过期时间
+        /// </summary>
+        public DateTime Expires { get; set; }
+    }
+}

+ 177 - 0
WebAPIBase.NetCore/Utils/Jwt/TokenHelper.cs

@@ -0,0 +1,177 @@
+using Microsoft.Extensions.Options;
+using Microsoft.IdentityModel.Tokens;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IdentityModel.Tokens.Jwt;
+using System.Linq;
+using System.Security.Claims;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WebAPIBase.Utils.Jwt
+{
+    /// <summary>
+    /// Token生成类
+    /// </summary>
+    public class TokenHelper : ITokenHelper
+    {
+        private readonly IOptions<JWTConfig> _options;
+        public TokenHelper(IOptions<JWTConfig> options)
+        {
+            _options = options;
+        }
+
+        /// <summary>
+        /// 根据一个对象通过反射提供负载生成token
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="user"></param>
+        /// <returns></returns>
+        public TnToken CreateToken<T>(T user) where T : class
+        {
+            //携带的负载部分,类似一个键值对
+            List<Claim> claims = new List<Claim>();
+            //这里我们用反射把model数据提供给它
+            foreach (var item in user.GetType().GetProperties())
+            {
+                object obj = item.GetValue(user);
+                string value = "";
+                if (obj != null)
+                    value = obj.ToString();
+
+                claims.Add(new Claim(item.Name, value));
+            }
+            //创建token
+            return CreateTokenString(claims);
+        }
+
+        /// <summary>
+        /// 根据键值对提供负载生成token
+        /// </summary>
+        /// <param name="keyValuePairs"></param>
+        /// <returns></returns>
+        public TnToken CreateToken(Dictionary<string, string> keyValuePairs)
+        {
+            //携带的负载部分,类似一个键值对
+            List<Claim> claims = new List<Claim>();
+            //这里我们通过键值对把数据提供给它
+            foreach (var item in keyValuePairs)
+            {
+                claims.Add(new Claim(item.Key, item.Value));
+            }
+            //创建token
+            return CreateTokenString(claims);
+        }
+        /// <summary>
+        /// 生成token
+        /// </summary>
+        /// <param name="claims">List的 Claim对象</param>
+        /// <returns></returns>
+        private TnToken CreateTokenString(List<Claim> claims)
+        {
+            var now = DateTime.Now;
+            var expires = now.Add(TimeSpan.FromMinutes(_options.Value.AccessTokenExpiresMinutes));
+            var token = new JwtSecurityToken(
+                issuer: _options.Value.Issuer,//Token发布者
+                audience: _options.Value.Audience,//Token接受者
+                claims: claims,//携带的负载
+                notBefore: now,//当前时间token生成时间
+                expires: expires,//过期时间
+                signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)), SecurityAlgorithms.HmacSha256));
+            return new TnToken { TokenStr = new JwtSecurityTokenHandler().WriteToken(token), Expires = expires };
+        }
+
+        /// <summary>
+        /// 验证身份 验证签名的有效性
+        /// </summary>
+        /// <param name="encodeJwt"></param>
+        /// <param name="validatePayLoad">自定义各类验证; 是否包含那种申明,或者申明的值, </param>
+        public bool ValiToken(string encodeJwt, Func<Dictionary<string, string>, bool> validatePayLoad = null)
+        {
+            var success = true;
+            var jwtArr = encodeJwt.Split('.');
+            if (jwtArr.Length < 3)//数据格式都不对直接pass
+            {
+                return false;
+            }
+            var header = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[0]));
+            var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[1]));
+            //配置文件中取出来的签名秘钥
+            var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(_options.Value.IssuerSigningKey));
+            //验证签名是否正确(把用户传递的签名部分取出来和服务器生成的签名匹配即可)
+            success = success && string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1])))));
+            if (!success)
+            {
+                return success;//签名不正确直接返回
+            }
+
+            //其次验证是否在有效期内(也应该必须)
+            var now = ToUnixEpochDate(DateTime.UtcNow);
+            success = success && (now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString()));
+
+            //不需要自定义验证不传或者传递null即可
+            if (validatePayLoad == null)
+                return true;
+
+            //再其次 进行自定义的验证
+            success = success && validatePayLoad(payLoad);
+
+            return success;
+        }
+        /// <summary>
+        /// 时间转换
+        /// </summary>
+        /// <param name="date"></param>
+        /// <returns></returns>
+        private long ToUnixEpochDate(DateTime date)
+        {
+            return (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);
+        }
+        /// <summary>
+        /// 校验token状态
+        /// </summary>
+        /// <param name="encodeJwt"></param>
+        /// <param name="validatePayLoad"></param>
+        /// <param name="action"></param>
+        /// <returns></returns>
+        public TokenType ValiTokenState(string encodeJwt, Func<Dictionary<string, string>, bool> validatePayLoad, Action<Dictionary<string, string>> action)
+        {
+            var jwtArr = encodeJwt.Split('.');
+            if (jwtArr.Length < 3)//数据格式都不对直接pass
+            {
+                return TokenType.Fail;
+            }
+            var header = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[0]));
+            var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[1]));
+            var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(_options.Value.IssuerSigningKey));
+            //验证签名是否正确(把用户传递的签名部分取出来和服务器生成的签名匹配即可)
+            if (!string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1]))))))
+            {
+                return TokenType.Fail;
+            }
+            //其次验证是否在有效期内(必须验证)
+            var now = ToUnixEpochDate(DateTime.UtcNow);
+            if (!(now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString())))
+            {
+                return TokenType.Expired;
+            }
+
+            //不需要自定义验证不传或者传递null即可
+            if (validatePayLoad == null)
+            {
+                action(payLoad);
+                return TokenType.Ok;
+            }
+            //再其次 进行自定义的验证
+            if (!validatePayLoad(payLoad))
+            {
+                return TokenType.Fail;
+            }
+            //可能需要获取jwt摘要里边的数据,封装一下方便使用
+            action(payLoad);
+            return TokenType.Ok;
+        }
+    }
+}

+ 18 - 0
WebAPIBase.NetCore/Utils/Jwt/TokenType.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WebAPIBase.Utils.Jwt
+{
+    /// <summary>
+    /// 返回类型成功失败
+    /// </summary>
+    public enum TokenType
+    {
+        Ok,
+        Fail,
+        Expired
+    }
+}

+ 28 - 0
WebAPIBase.NetCore/Utils/NlogHelper.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WebAPIBase.Utils
+{
+    public class NlogHelper
+    {
+        /// <summary>
+        /// 定时任务日志
+        /// </summary>
+        public static NLog.Logger quartzLogger = NLog.LogManager.GetLogger("quartz");
+        /// <summary>
+        /// mylog日志
+        /// </summary>
+        public static NLog.Logger myLogger = NLog.LogManager.GetLogger("mylog");
+
+        /// <summary>
+        /// sql日志
+        /// </summary>
+        public static NLog.Logger sqlLogger = NLog.LogManager.GetLogger("sql"); 
+
+
+         
+    }
+}

+ 124 - 0
WebAPIBase.NetCore/WebAPIBase.NetCore.Enties/DTO/MaterialOutDtlDTO.cs

@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Sugar.Enties
+{
+    public class MaterialOutDtlDTO
+    {
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:False
+        /// </summary>      
+        public string MaterialOutDtlCode { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public string MaterialOutCode { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public string MaterialCode { get; set; }
+        /// <summary>
+        /// 材料名
+        /// </summary>
+        public string MaterialName { get; set; }
+        /// <summary>
+        /// 单位
+        /// </summary>
+        public string Unit { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public string MaterialInDtlCode { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public decimal? OutQty { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public decimal? OutPrice { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public decimal? OutMoney { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public string ArticleCode { get; set; }
+
+        /// <summary>
+        /// Desc:材料计划单号
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public string MaterialBudgetCode { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public decimal? OutPriceMoney { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public decimal? OutCash { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:0
+        /// Nullable:True
+        /// </summary>           
+        public decimal? AlreadyDeductNum { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:0
+        /// Nullable:True
+        /// </summary>           
+        public decimal? AlreadyDeductCash { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:0
+        /// Nullable:True
+        /// </summary>           
+        public decimal? AlreadyDeductMoney { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:0
+        /// Nullable:True
+        /// </summary>           
+        public int? IsDeductOver { get; set; }
+    }
+}

+ 74 - 0
WebAPIBase.NetCore/WebAPIBase.NetCore/Filter/TokenFilter.cs

@@ -0,0 +1,74 @@
+using Microsoft.AspNetCore.Mvc.Filters;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using WebAPIBase.Utils.Jwt;
+using WebAPIBase.Utils;
+using Microsoft.AspNetCore.Mvc;
+
+namespace WebAPIBase.API.Filter
+{
+    /// <summary>
+    /// 过滤器实现通用token验证
+    /// </summary>
+    public class TokenFilter : Attribute, IActionFilter
+    {
+        private ITokenHelper tokenHelper;
+        /// <summary>
+        /// 滤器实现通用token验证
+        /// </summary>
+        /// <param name="_tokenHelper"></param>
+        public TokenFilter(ITokenHelper _tokenHelper) //通过依赖注入得到数据访问层实例
+        {
+            tokenHelper = _tokenHelper;
+        }
+
+        public void OnActionExecuted(ActionExecutedContext context)
+        {
+
+        }
+        public void OnActionExecuting(ActionExecutingContext context)
+        {
+            ApiResponse ret = new ApiResponse();
+            //获取token
+            //object tokenobj = context.ActionArguments["token"];//前端地址栏参数传参
+            object tokenobj = context.HttpContext.Request.Headers["X-Token"].ToString();//前端写在header里面获取的
+            if (tokenobj == null)
+            {
+                ret.IsSuccess = false;
+                ret.Code = 201;
+                ret.ErrMsg = "token不能为空";
+                context.Result = new JsonResult(ret);
+                return;
+            }
+
+            string token = tokenobj.ToString();
+
+            string userId = "";
+            //验证jwt,同时取出来jwt里边的用户ID
+            TokenType tokenType = tokenHelper.ValiTokenState(token, a => a["iss"] == "lutao" && a["aud"] == "haodegongchengyun", action => { userId = action["UserID"]; });
+            if (tokenType == TokenType.Fail)
+            {
+                ret.IsSuccess = false;
+                ret.Code = 202;
+                ret.ErrMsg = "token验证失败";
+                context.Result = new JsonResult(ret);
+                return;
+            }
+            if (tokenType == TokenType.Expired)
+            {
+                ret.IsSuccess = false;
+                ret.Code = 205;
+                ret.ErrMsg = "token已经过期";
+                context.Result = new JsonResult(ret);
+            }
+            if (!string.IsNullOrEmpty(userId))
+            {
+                //给控制器传递参数(需要什么参数其实可以做成可以配置的,在过滤器里边加字段即可)
+                //context.ActionArguments.Add("userId", Convert.ToInt32(userId));
+            }
+        }
+    }
+}