黄贺彬 6 years ago
parent
commit
7a6a1d08fe
28 changed files with 733 additions and 1 deletions
  1. 53 0
      TEAMModelOS.Extension.JwtAuth/Filters/JwtAuthorizationFilter.cs
  2. 83 0
      TEAMModelOS.Extension.JwtAuth/JwtAuthExtension.cs
  3. 74 0
      TEAMModelOS.Extension.JwtAuth/JwtHelper/JwtHelper.cs
  4. 27 0
      TEAMModelOS.Extension.JwtAuth/Models/ClaimModel.cs
  5. 12 0
      TEAMModelOS.Extension.JwtAuth/Models/HttpConstant.cs
  6. 12 0
      TEAMModelOS.Extension.JwtAuth/Models/JwtClient.cs
  7. 13 0
      TEAMModelOS.Extension.JwtAuth/Models/JwtResponse.cs
  8. 30 0
      TEAMModelOS.Extension.JwtAuth/Models/JwtSetting.cs
  9. 14 1
      TEAMModelOS.Extension.JwtAuth/TEAMModelOS.Extension.JwtAuth.csproj
  10. 38 0
      TEAMModelOS.Extension.Language/Implements/LanguageService.cs
  11. 12 0
      TEAMModelOS.Extension.Language/Interfaces/ILanguageService.cs
  12. 18 0
      TEAMModelOS.Extension.Language/LanguageExtension.cs
  13. 10 0
      TEAMModelOS.Extension.Language/Model/SmsCountryCode.cs
  14. 3 0
      TEAMModelOS.Extension.Language/README.md
  15. 6 0
      TEAMModelOS.Extension.Language/TEAMModelOS.Extension.Language.csproj
  16. 152 0
      TEAMModelOS.Extension.MessagePush/Implements/SendCloudService.cs
  17. 42 0
      TEAMModelOS.Extension.MessagePush/Interfaces/ISendCloudService.cs
  18. 20 0
      TEAMModelOS.Extension.MessagePush/MessagePushExtension.cs
  19. 30 0
      TEAMModelOS.Extension.MessagePush/Model/SendCloudResponse.cs
  20. 36 0
      TEAMModelOS.Extension.MessagePush/Model/SmsConfig.cs
  21. 12 0
      TEAMModelOS.Extension.MessagePush/Model/SmsSendCloud.cs
  22. 6 0
      TEAMModelOS.Extension.MessagePush/TEAMModelOS.Extension.MessagePush.csproj
  23. 5 0
      TEAMModelOS.Model.Analysis/TEAMModelOS.Model.Analysis.csproj
  24. 5 0
      TEAMModelOS.Model.Common/TEAMModelOS.Model.Common.csproj
  25. 5 0
      TEAMModelOS.Model.Syllabus/TEAMModelOS.Model.Syllabus.csproj
  26. 5 0
      TEAMModelOS.Service.Analysis/TEAMModelOS.Service.Analysis.csproj
  27. 5 0
      TEAMModelOS.Service.Common/TEAMModelOS.Service.Common.csproj
  28. 5 0
      TEAMModelOS.Service.Syllabus/TEAMModelOS.Service.Syllabus.csproj

+ 53 - 0
TEAMModelOS.Extension.JwtAuth/Filters/JwtAuthorizationFilter.cs

@@ -0,0 +1,53 @@
+using TEAMModelOS.Extension.JwtAuth.Models;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Security.Claims;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.Extension.JwtAuth.Filters
+{
+    public class JwtAuthorizationFilter
+    {
+        private readonly RequestDelegate _next;
+        public JwtAuthorizationFilter(RequestDelegate next)
+        {
+            _next = next;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="httpContext"></param>
+        /// <returns></returns>
+        public Task Invoke(HttpContext httpContext)
+        {
+            //检测是否包含'Authorization'请求头,如果不包含则直接放行
+            if (!httpContext.Request.Headers.ContainsKey(HttpConstant.Authorization) &&!httpContext.Request.Query.ContainsKey(HttpConstant.access_token))
+            {
+                return _next(httpContext);
+            }
+            var tokenHeader = "";
+            if (httpContext.Request.Query.ContainsKey(HttpConstant.access_token))
+            {
+                tokenHeader = httpContext.Request.Query[HttpConstant.access_token];
+                tokenHeader = tokenHeader.ToString().Trim();
+            }
+            if (httpContext.Request.Headers.ContainsKey(HttpConstant.Authorization)) {
+                tokenHeader = httpContext.Request.Headers[HttpConstant.Authorization];
+                tokenHeader = tokenHeader.ToString().Substring("Bearer ".Length).Trim();
+            }
+
+            ClaimModel claimModel = JwtHelper.JwtHelper.SerializeJWT(tokenHeader);
+
+            //将tokenModel存入缓存中
+            //授权
+            //已经弃用该方式获取User信息,采用官方认证,必须在上边ConfigureService 中,配置JWT的认证服务 (.AddAuthentication 和 .AddJwtBearer 二者缺一不可)
+            //var identity = new ClaimsIdentity(claimModel.Claims);
+            //var principal = new ClaimsPrincipal(identity);
+            //httpContext.User = principal;
+            return _next(httpContext);
+        }
+    }
+}

+ 83 - 0
TEAMModelOS.Extension.JwtAuth/JwtAuthExtension.cs

@@ -0,0 +1,83 @@
+using TEAMModelOS.Extension.JwtAuth.Models;
+using IdentityModel;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.IdentityModel.Tokens;
+using System;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.Extension.JwtAuth
+{
+    public static class JwtAuthExtension
+    {
+        public static void JwtAuth(this IServiceCollection services , IConfigurationSection configuration)
+        {
+            services.Configure<JwtSetting>(configuration);
+            var creds = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["SecurityKey"]));
+            // 令牌验证参数
+            var tokenValidationParameters = new TokenValidationParameters
+            {
+                NameClaimType = JwtClaimTypes.Name,
+                RoleClaimType = JwtClaimTypes.Role,
+                ValidateIssuerSigningKey = true,
+                IssuerSigningKey = creds,
+                ValidateIssuer = true,
+                ValidIssuer = configuration["Issuer"],//发行人
+                ValidateAudience = true,
+                ValidAudience = configuration["Audience"],//订阅人
+                                                           // 是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
+                ValidateLifetime = true,
+                //允许的服务器时间偏移量
+                ClockSkew = TimeSpan.Zero,
+                //是否要求Token的Claims中必须包含Expires
+                RequireExpirationTime = true,
+            };
+            services.AddAuthentication(x => {
+                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
+                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
+            }).AddJwtBearer(o =>
+            {
+                o.TokenValidationParameters = tokenValidationParameters;
+                o.Events = new JwtBearerEvents
+                {
+                    OnAuthenticationFailed = context =>
+                    {
+                        // 如果过期,则把<是否过期>添加到,返回头信息中
+                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
+                        {
+                            context.Response.Headers.Add("Token-Expired", "true");
+                        }
+                        return Task.CompletedTask;
+                    },
+                    //Url中添加access_token=[token],直接在浏览器中访问
+                    OnMessageReceived = context => {
+                        context.Token = context.Request.Query["access_token"];
+                        return Task.CompletedTask;
+                    },
+                    //URL未授权调用
+                    OnChallenge = context => {
+                        return Task.CompletedTask;
+                    },
+                    //在Token验证通过后调用
+                    OnTokenValidated = context => {
+                        //编写业务
+                        return Task.CompletedTask;
+                    },
+
+                };
+            });
+            //自定义授权
+            services.AddAuthorization(auth =>
+            {
+                auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
+                    .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
+                    .RequireAuthenticatedUser()
+                    .Build());
+            });
+        }
+        
+    }
+}

+ 74 - 0
TEAMModelOS.Extension.JwtAuth/JwtHelper/JwtHelper.cs

@@ -0,0 +1,74 @@
+using TEAMModelOS.Extension.JwtAuth.Models;
+using IdentityModel;
+using Microsoft.IdentityModel.Tokens;
+using System;
+using System.Collections.Generic;
+using System.IdentityModel.Tokens.Jwt;
+using System.Linq;
+using System.Security.Claims;
+using System.Text;
+using TEAMModelOS.Helper.Common.DateTimeHelper;
+
+namespace TEAMModelOS.Extension.JwtAuth.JwtHelper
+{
+    public class JwtHelper
+    {
+        /// <summary>
+        /// 颁发JWT Token
+        /// </summary>
+        /// <param name="claimModel"></param>
+        /// <param name="tokenModel"></param>
+        /// <returns></returns>
+        public static JwtResponse IssueJWT(ClaimModel claimModel, JwtSetting setting)
+        {
+           // JwtClient jwtClient = null;
+
+            JwtClient jwtClient= setting.JwtClient.Where(x => x.Name.Equals(claimModel.Scope)).First();
+            //foreach (JwtClient client in setting.JwtClient) {
+            //    if (claimModel.Scope.Equals(client.Name)) {
+            //        jwtClient = client;
+            //        break; 
+            //    }
+            //}
+            List<Claim> claims = new List<Claim>();
+            var dateTime = DateTimeHelper.ConvertToTimeStamp10(DateTime.Now);
+            claims.AddRange(claimModel.Claims);
+            claims.Add(new Claim(JwtClaimTypes.IssuedAt, dateTime + "", ClaimValueTypes.Integer64));
+            claims.Add(new Claim(JwtClaimTypes.NotBefore, dateTime + "", ClaimValueTypes.Integer64));
+            claims.Add(new Claim(JwtClaimTypes.Expiration, dateTime + jwtClient.Exp + "", ClaimValueTypes.Integer64));
+            claims.Add(new Claim(JwtClaimTypes.Audience, setting.Audience));
+            claims.Add(new Claim(JwtClaimTypes.Issuer, setting.Issuer));
+            claims.Add(new Claim(JwtClaimTypes.Scope, claimModel.Scope));
+            claims.AddRange(claimModel.Roles.ToArray().Select(s=>new Claim(JwtClaimTypes.Role,s)));
+            var creds = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecurityKey)), SecurityAlgorithms.HmacSha512);
+            var jwt = new JwtSecurityToken(
+                claims:claims,
+                signingCredentials:creds
+                );
+            var jwtHandler = new JwtSecurityTokenHandler();
+              jwtHandler.WriteToken(jwt);
+
+
+            return new JwtResponse {
+                access_token = jwtHandler.WriteToken(jwt),
+                scope = claimModel.Scope
+            };
+        }
+        /// <summary>
+        /// 解析jwt
+        /// </summary>
+        /// <param name="jwtStr"></param>
+        /// <returns></returns>
+        public static ClaimModel SerializeJWT(string jwtStr)
+        {
+            var jwtHandler = new JwtSecurityTokenHandler();
+            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
+            ClaimModel claimModel = new ClaimModel();
+            object role = new object();
+            claimModel.Claims = jwtToken.Claims.ToList();
+            jwtToken.Payload.TryGetValue("role", out role);
+            if(role!=null)claimModel.Roles=role.ToString().Split(",").ToList();
+            return claimModel;
+        }
+    }
+}

+ 27 - 0
TEAMModelOS.Extension.JwtAuth/Models/ClaimModel.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Security.Claims;
+
+namespace TEAMModelOS.Extension.JwtAuth.Models
+{
+    public class ClaimModel
+    {
+        public ClaimModel() {
+            Claims = new List<Claim>();
+            Roles = new List<string>();
+        }
+
+        /// <summary>
+        /// 用户身份信息
+        /// </summary>
+        public List<Claim> Claims { get; set; }
+        /// <summary>
+        /// 用户角色信息
+        /// </summary>
+        public List<string> Roles { get; set; }
+        /// <summary>
+        /// 令牌类型
+        /// </summary>
+        public string Scope { get; set; }
+    }
+}

+ 12 - 0
TEAMModelOS.Extension.JwtAuth/Models/HttpConstant.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.Extension.JwtAuth.Models
+{
+    public class HttpConstant
+    {
+        public static readonly string Authorization = "Authorization";
+        public static readonly string access_token = "access_token";
+    }
+}

+ 12 - 0
TEAMModelOS.Extension.JwtAuth/Models/JwtClient.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.Extension.JwtAuth.Models
+{
+    public class JwtClient
+    {
+        public string Name { get; set; }
+        public double Exp { get; set; }
+    }
+}

+ 13 - 0
TEAMModelOS.Extension.JwtAuth/Models/JwtResponse.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.Extension.JwtAuth.Models
+{
+    public class JwtResponse
+    {
+        public string access_token { get; set; }
+        public string token_type { get; set; } = "Bearer";
+        public string scope { get; set; }
+    }
+}

+ 30 - 0
TEAMModelOS.Extension.JwtAuth/Models/JwtSetting.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.Extension.JwtAuth.Models
+{
+    public class JwtSetting
+    {
+        /// <summary>
+        /// 项目名称
+        /// </summary>
+       // public string Project { get; set; }
+        /// <summary>
+        /// JwtClient
+        /// </summary>
+        public List<JwtClient> JwtClient { get; set; }
+        /// <summary>
+        /// WT的接收对象
+        /// </summary>
+        public string Audience { get; set; }
+        /// <summary>
+        /// JWT的签发主体
+        /// </summary>
+        public string Issuer { get; set; }
+        /// <summary>
+        /// JWT Secret Key
+        /// </summary>
+        public string SecurityKey { get; set; }
+    }
+}

+ 14 - 1
TEAMModelOS.Extension.JwtAuth/TEAMModelOS.Extension.JwtAuth.csproj

@@ -1,7 +1,20 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
 
   <PropertyGroup>
   <PropertyGroup>
     <TargetFramework>netcoreapp2.2</TargetFramework>
     <TargetFramework>netcoreapp2.2</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
+  <ItemGroup>
+    <PackageReference Include="IdentityModel" Version="3.10.6" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.2.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="2.2.0" />
+    <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
+    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\TEAMModelOS.Helper.Common\TEAMModelOS.Helper.Common.csproj" />
+  </ItemGroup>
+
 </Project>
 </Project>

+ 38 - 0
TEAMModelOS.Extension.Language/Implements/LanguageService.cs

@@ -0,0 +1,38 @@
+using TEAMModelOS.Extension.Language.Interfaces;
+using TEAMModelOS.Extension.Language.Model;
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
+
+namespace TEAMModelOS.Extension.Language.Implements
+{
+    public class LanguageService : ILanguageService
+    {
+        private Dictionary<string, SmsCountryCode> smsMap { get; set; }
+        public List<SmsCountryCode> countryCodes;
+
+        public LanguageService(IOptions<List<SmsCountryCode>> _option)
+        {
+            countryCodes = _option.Value;
+           
+        }
+        private LanguageService SmsLanguage()
+        {
+            foreach (SmsCountryCode sms in countryCodes) {
+                if (this.smsMap == null)
+                {
+                    smsMap = new Dictionary<string, SmsCountryCode>();
+                }
+                if (!smsMap.ContainsKey(sms.CountryCode))
+                {
+                    smsMap.Add(sms.CountryCode, sms);
+                }
+            }
+            return this;
+        }
+        public Dictionary<string, SmsCountryCode> GetSmsLanguage()
+        {
+            SmsLanguage();
+            return smsMap;
+        }
+    }
+}

+ 12 - 0
TEAMModelOS.Extension.Language/Interfaces/ILanguageService.cs

@@ -0,0 +1,12 @@
+using TEAMModelOS.Extension.Language.Model;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.Extension.Language.Interfaces
+{
+    public interface ILanguageService
+    {
+        Dictionary<string, SmsCountryCode> GetSmsLanguage();
+    }
+}

+ 18 - 0
TEAMModelOS.Extension.Language/LanguageExtension.cs

@@ -0,0 +1,18 @@
+using TEAMModelOS.Extension.Language.Implements;
+using TEAMModelOS.Extension.Language.Interfaces;
+using TEAMModelOS.Extension.Language.Model;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using System.Collections.Generic;
+
+namespace TEAMModelOS.Extension.Language
+{
+    public static class LanguageExtension
+    {
+        public static void AddLanguage(this IServiceCollection services, IConfigurationSection LangConfiguration)
+        {
+            services.Configure<List<SmsCountryCode>>(LangConfiguration);
+            services.AddSingleton<ILanguageService, LanguageService>();
+        }
+    }
+}

+ 10 - 0
TEAMModelOS.Extension.Language/Model/SmsCountryCode.cs

@@ -0,0 +1,10 @@
+namespace TEAMModelOS.Extension.Language.Model
+{
+    public  class SmsCountryCode
+    {
+        public string Name { get; set; }
+        public string CountryCode { get; set; }
+        public string Language { get; set; }
+        public string SmsLang { get; set; }
+    }
+}

+ 3 - 0
TEAMModelOS.Extension.Language/README.md

@@ -0,0 +1,3 @@
+Install-Package Microsoft.Extensions.Options.ConfigurationExtensions
+Install-Package Microsoft.Extensions.DependencyInjection
+Install-Package Microsoft.Extensions.Configuration

+ 6 - 0
TEAMModelOS.Extension.Language/TEAMModelOS.Extension.Language.csproj

@@ -4,4 +4,10 @@
     <TargetFramework>netcoreapp2.2</TargetFramework>
     <TargetFramework>netcoreapp2.2</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
+    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" />
+  </ItemGroup>
+
 </Project>
 </Project>

+ 152 - 0
TEAMModelOS.Extension.MessagePush/Implements/SendCloudService.cs

@@ -0,0 +1,152 @@
+
+using TEAMModelOS.Extension.MessagePush.Interfaces;
+using TEAMModelOS.Extension.MessagePush.Model;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using TEAMModelOS.Extension.Language.Interfaces;
+using TEAMModelOS.Module.AzureTable.Interfaces;
+using Microsoft.Extensions.Options;
+using TEAMModelOS.Extension.Language.Model;
+using TEAMModelOS.Helper.Common.JsonHelper;
+using TEAMModelOS.Helper.Security.Md5Hash;
+using TEAMModelOS.Helper.Network.HttpHelper;
+
+namespace TEAMModelOS.Extension.MessagePush.Implements
+{
+    public class SendCloudService : ISendCloudService
+    {
+        public SmsSendCloud smsSendCloud;
+        public ILanguageService _languageService;
+        public IAzureTableDBRepository _azureTableDBRepository;
+        public SendCloudService(IOptions<SmsSendCloud> _option, ILanguageService languageService , IAzureTableDBRepository azureTableDBRepository )
+        {
+            _azureTableDBRepository = azureTableDBRepository;
+            _languageService = languageService;
+            smsSendCloud = _option.Value;
+        }
+
+
+        public List<Dictionary<string, string>> Languages { get; set; } = new List<Dictionary<string, string>>
+        {
+            new Dictionary<string, string> { { "name", "简体中文" }, { "code","CHS"  } },
+            new Dictionary<string, string> { { "name", "繁体中文" }, { "code","CHT" } },
+            new Dictionary<string, string> { { "name", "英语" }, { "code","EN"  } } };
+        public List<Dictionary<string, string>> BizCodes { get; set; } = new List<Dictionary<string, string>>
+        {
+            //new Dictionary<string, string> { { "name", "验证码业务" }, { "code", "Captcha" } },
+            new Dictionary<string, string> { { "name", "报名通知业务" }, { "code", "SignUp" } }
+        };
+        public async Task<List<SmsConfig>> SaveOrUpdateSmsConfig(List<SmsConfig> configs) {
+            return await _azureTableDBRepository.SaveOrUpdateAll<SmsConfig>(configs); 
+        }
+        public async Task<List<SmsConfig>> InitSmsConfig(string BizNum)
+        {
+            List<SmsConfig> smsConfigs = new List<SmsConfig>() ;
+            List<SmsConfig> SaveSmsConfigs = new List<SmsConfig>();
+            foreach (Dictionary<string, string> BizCode in BizCodes) {
+                foreach (Dictionary<string, string> Language in Languages) {
+                    Dictionary<string, object> dict = new Dictionary<string, object>
+                    {
+                        { "BizNum", BizNum },{ "BizCode", BizCode["code"] }, { "Language", Language["code"] } ,
+                    };
+                    SmsConfig smsConfig = await _azureTableDBRepository.FindOneByDict<SmsConfig>(dict);
+
+                    if (smsConfig != null && smsConfig.RowKey != null)
+                    {
+                        smsConfigs.Add(smsConfig);
+                    }
+                    else {
+                        DateTimeOffset now = DateTimeOffset.Now;
+                        SmsConfig SaveSmsConfig = new SmsConfig {
+                            RowKey = BizNum + "-" + BizCode["code"] + "-" + Language["code"],
+                            PartitionKey = BizNum,
+                            Language = Language["code"],
+                            LanguageName = Language["name"],
+                            BizCode = BizCode["code"],
+                            BizName = BizCode["name"],
+                            BizNum = BizNum,
+                            Template = null,
+                            Timestamp= now
+                        };
+                        SaveSmsConfigs.Add(SaveSmsConfig);
+                        smsConfigs.Add(SaveSmsConfig);
+                    }
+                }
+            }
+            if (SaveSmsConfigs.Count > 0) {
+               await _azureTableDBRepository.SaveOrUpdateAll<SmsConfig>(SaveSmsConfigs);
+            }
+            return smsConfigs; 
+        }
+        /// <summary>
+        /// https://sendcloud.kf5.com/posts/view/1074678/
+        /// </summary>
+        /// <param name="BizCode"></param>
+        /// <param name="CountryCode"></param>
+        /// <param name="phone"></param>
+        /// <param name="vars"></param>
+        /// <returns></returns>
+        public async Task<SendCloudResponse> SendSmsByBizCode(string  BizNum  , string BizCode, int CountryCode, string phone, Dictionary<string, string> vars = null)
+        {
+            SmsCountryCode code = null;
+            bool flag = _languageService.GetSmsLanguage().TryGetValue(CountryCode + "", out code);
+            string SmsLang = "EN";
+            int templateId = 0;
+            if (flag)
+            {
+                SmsLang = code.SmsLang;
+            }
+            Dictionary<string, object> dict = new Dictionary<string, object>
+            {
+                { "BizNum", BizNum },{ "BizCode", BizCode }, { "Language", SmsLang } ,
+            };
+            SmsConfig smsConfig   =  await _azureTableDBRepository.FindOneByDict<SmsConfig>(dict);
+
+            if (smsConfig != null && smsConfig.RowKey != null )
+            {
+                //默认调用英文,不管是否包含,发送时会去处理相关信息
+                int.TryParse(smsConfig.Template ,out templateId);
+            }
+            //else {
+            //    throw new BizException("");
+            //   //  templateId = smsSendCloud.SmsCode[code.SmsLang];
+            //}
+            int msgType = 0;
+            if (CountryCode != 86)
+            {
+                msgType = 2;
+                return await SendSms(templateId, "00" + CountryCode + phone, vars, msgType);
+            }
+            else
+            {
+                return await SendSms(templateId, phone, vars, msgType);
+            }
+            
+        }
+        public async Task<SendCloudResponse> SendSms(int templateId, string phone, Dictionary<string, string> vars = null, int msgType = 0)
+        {
+            List<KeyValuePair<string, string>> paramList = new List<KeyValuePair<string, string>>
+            {
+                new KeyValuePair<string, string>("msgType", msgType+""),//0表示短信, 1表示彩信,2表示国际短信, 默认值为0
+                new KeyValuePair<string, string>("phone", phone),
+                new KeyValuePair<string, string>("smsUser", smsSendCloud.SmsUser),
+                new KeyValuePair<string, string>("templateId", templateId+""),
+            };
+            if (vars != null)
+            {
+                paramList.Add(new KeyValuePair<string, string>("vars", MessagePackHelper.ObjectToJson(vars)));
+            }
+            var param_str = "";
+            foreach (var param in paramList)
+            {
+                param_str += param.Key.ToString() + "=" + param.Value.ToString() + "&";
+            }
+            string sign_str = smsSendCloud.SmsKey + "&" + param_str + smsSendCloud.SmsKey;
+            string sign = Md5Hash.Encrypt(sign_str);
+            paramList.Add(new KeyValuePair<string, string>("signature", sign));
+            string result = await HttpHelper.HttpPostAsync(smsSendCloud.SmsUrl, paramList);
+            return MessagePackHelper.JsonToObject<SendCloudResponse>(result);
+        }
+    }
+}

+ 42 - 0
TEAMModelOS.Extension.MessagePush/Interfaces/ISendCloudService.cs

@@ -0,0 +1,42 @@
+using TEAMModelOS.Extension.MessagePush.Model;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.Extension.MessagePush.Interfaces
+{
+    public interface ISendCloudService
+    {
+        /// <summary>
+        /// 发送普通文字短信
+        /// </summary>
+        /// <param name="templateId">模板ID</param>
+        /// <param name="msgType">消息类型0表示短信, 1表示彩信,2表示国际短信, 默认值为0 </param>
+        /// <param name="phone">信人手机号,多个手机号用逗号,分隔,每次调用最大支持2000,更多地址建议使用联系人列表功能</param>
+        /// <param name="vars">替换变量的json串 ,含有特殊字符 请 urlencode ,{"name": "lucy"} or {"%money%": "100"}</param>
+        /// <returns></returns>
+         Task<SendCloudResponse> SendSms(int templateId, string phone, Dictionary<string, string> vars =null , int msgType = 0);
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="BizCode">业务Code</param>
+        /// <param name="CountryCode">国家或地区编码</param>
+        /// <param name="phone">手机号</param>
+        /// <param name="vars">替换变量的json串 ,含有特殊字符 请 urlencode ,{"name": "lucy"} or {"%money%": "100"}</param>
+        /// <returns></returns>
+        Task<SendCloudResponse> SendSmsByBizCode(string BizNum  , string BizCode, int CountryCode, string phone, Dictionary<string, string> vars = null);
+        /// <summary>
+        /// 根据业务流水号初始化短信配置
+        /// </summary>
+        /// <param name="BizNum"></param>
+        /// <returns></returns>
+        Task<List<SmsConfig>> InitSmsConfig(string BizNum);
+        /// <summary>
+        /// 更新或保存
+        /// </summary>
+        /// <param name="configs"></param>
+        /// <returns></returns>
+        Task<List<SmsConfig>> SaveOrUpdateSmsConfig(List<SmsConfig> configs);
+    }
+}

+ 20 - 0
TEAMModelOS.Extension.MessagePush/MessagePushExtension.cs

@@ -0,0 +1,20 @@
+using TEAMModelOS.Extension.MessagePush.Implements;
+using TEAMModelOS.Extension.MessagePush.Interfaces;
+using TEAMModelOS.Extension.MessagePush.Model;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.Extension.MessagePush
+{
+    public static class MessagePushExtension
+    {
+        public static void SendCloud(this IServiceCollection services, IConfigurationSection configuration)
+        {
+            services.Configure<SmsSendCloud>(configuration);
+            services.AddSingleton<ISendCloudService, SendCloudService>();
+        }
+    }
+}

+ 30 - 0
TEAMModelOS.Extension.MessagePush/Model/SendCloudResponse.cs

@@ -0,0 +1,30 @@
+using MessagePack;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TEAMModelOS.Extension.MessagePush.Model
+{
+    [MessagePackObject(keyAsPropertyName: true)]
+    public  class SendCloudResponse
+    {
+        public string message { get; set; }
+        public Info info { get; set; }
+        public bool result { get; set; }
+        public int  statusCode { get; set; }
+    }
+    [MessagePackObject(keyAsPropertyName: true)]
+    public class Info
+    {
+        public int successCount { get; set; }
+        public string[] smsIds { get; set; }
+        public int failedCount { get; set; }
+        public Item[] items { get; set; }
+    }
+    [MessagePackObject(keyAsPropertyName: true)]
+    public class Item
+    {
+        public string phone { get; set; }
+        public string message { get; set; }
+    }
+}

+ 36 - 0
TEAMModelOS.Extension.MessagePush/Model/SmsConfig.cs

@@ -0,0 +1,36 @@
+
+using Microsoft.WindowsAzure.Storage.Table;
+
+namespace TEAMModelOS.Extension.MessagePush.Model
+{
+    /// <summary>
+    /// 短信配置
+    /// </summary>
+    public class SmsConfig : TableEntity
+    {
+        /// <summary>
+        /// 语言
+        /// </summary>
+        public string Language { get; set; }
+        /// <summary>
+        /// 语言名称
+        /// </summary>
+        public string LanguageName { get; set; }
+        /// <summary>
+        /// 业务code
+        /// </summary>
+        public string BizCode { get; set; }
+        /// <summary>
+        /// 业务名称
+        /// </summary>
+        public string BizName { get; set; }
+        /// <summary>
+        /// 模板ID
+        /// </summary>
+        public string Template { get; set; }
+        /// <summary>
+        /// 业务流水号
+        /// </summary>
+        public string BizNum { get; set; }
+    }
+}

+ 12 - 0
TEAMModelOS.Extension.MessagePush/Model/SmsSendCloud.cs

@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+
+namespace TEAMModelOS.Extension.MessagePush.Model
+{
+    public class SmsSendCloud
+    {
+        public string SmsUrl { get; set; }
+        public string SmsUser { get; set; }
+        public string SmsKey { get; set; }
+       
+    }
+}

+ 6 - 0
TEAMModelOS.Extension.MessagePush/TEAMModelOS.Extension.MessagePush.csproj

@@ -4,4 +4,10 @@
     <TargetFramework>netcoreapp2.2</TargetFramework>
     <TargetFramework>netcoreapp2.2</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
+  <ItemGroup>
+    <ProjectReference Include="..\TEAMModelOS.Extension.Language\TEAMModelOS.Extension.Language.csproj" />
+    <ProjectReference Include="..\TEAMModelOS.Helper.Network\TEAMModelOS.Helper.Network.csproj" />
+    <ProjectReference Include="..\TEAMModelOS.Module.AzureTable\TEAMModelOS.Module.AzureTable.csproj" />
+  </ItemGroup>
+
 </Project>
 </Project>

+ 5 - 0
TEAMModelOS.Model.Analysis/TEAMModelOS.Model.Analysis.csproj

@@ -4,4 +4,9 @@
     <TargetFramework>netcoreapp2.2</TargetFramework>
     <TargetFramework>netcoreapp2.2</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
+  <ItemGroup>
+    <Folder Include="Models\" />
+    <Folder Include="Dtos\" />
+  </ItemGroup>
+
 </Project>
 </Project>

+ 5 - 0
TEAMModelOS.Model.Common/TEAMModelOS.Model.Common.csproj

@@ -4,4 +4,9 @@
     <TargetFramework>netcoreapp2.2</TargetFramework>
     <TargetFramework>netcoreapp2.2</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
+  <ItemGroup>
+    <Folder Include="Dtos\" />
+    <Folder Include="Models\" />
+  </ItemGroup>
+
 </Project>
 </Project>

+ 5 - 0
TEAMModelOS.Model.Syllabus/TEAMModelOS.Model.Syllabus.csproj

@@ -4,4 +4,9 @@
     <TargetFramework>netcoreapp2.2</TargetFramework>
     <TargetFramework>netcoreapp2.2</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
+  <ItemGroup>
+    <Folder Include="Dtos\" />
+    <Folder Include="Models\" />
+  </ItemGroup>
+
 </Project>
 </Project>

+ 5 - 0
TEAMModelOS.Service.Analysis/TEAMModelOS.Service.Analysis.csproj

@@ -4,4 +4,9 @@
     <TargetFramework>netcoreapp2.2</TargetFramework>
     <TargetFramework>netcoreapp2.2</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
+  <ItemGroup>
+    <Folder Include="Interfaces\" />
+    <Folder Include="Implements\" />
+  </ItemGroup>
+
 </Project>
 </Project>

+ 5 - 0
TEAMModelOS.Service.Common/TEAMModelOS.Service.Common.csproj

@@ -4,4 +4,9 @@
     <TargetFramework>netcoreapp2.2</TargetFramework>
     <TargetFramework>netcoreapp2.2</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
+  <ItemGroup>
+    <Folder Include="Implements\" />
+    <Folder Include="Interfaces\" />
+  </ItemGroup>
+
 </Project>
 </Project>

+ 5 - 0
TEAMModelOS.Service.Syllabus/TEAMModelOS.Service.Syllabus.csproj

@@ -4,4 +4,9 @@
     <TargetFramework>netcoreapp2.2</TargetFramework>
     <TargetFramework>netcoreapp2.2</TargetFramework>
   </PropertyGroup>
   </PropertyGroup>
 
 
+  <ItemGroup>
+    <Folder Include="Implements\" />
+    <Folder Include="Interfaces\" />
+  </ItemGroup>
+
 </Project>
 </Project>