刹那的菜鸟

博客园 首页 新随笔 联系 管理

1、手动创建
2、命令行从模板创建

手动创建就是复制一个官方的任意模块。
这个不细说。

2、我是从命令行创建的。 首先要安装orchard core的模板
dotnet new install OrchardCore.ProjectTemplates::2.0.2

参考: https://docs.orchardcore.net/en/latest/getting-started/templates/

在自己项目的文件夹 运行cmd命令 ,然后执行创建一个新的模块 : Super.Aliyun.SMS

模板可以选择 ocmodulecms 跟ocmodulemvc 前者是cms的模块,后者是mvc的。 cms自带一些基础的路由
然后在vs的项目 添加该模块,以下是创建的默认文件:

可以修改 Manifest.cs (清单)的内容,比如 作者,还有功能名称。
默认的访问路径是: 模块名称/控制器/方法
我这边创建的是 Super.Aliyun.SMS
所以默认是
http://localhost:5111/Super.Aliyun.SMS/Home/Index

现在开始。
引入orchardcore的sms模块

接下去只要实现阿里云的sms服务,按官方的说明:
要实现自己想要的
services.AddSmsProviderOptionsConfiguration<YourCustomImplemenation>()
`public class TwilioProviderOptionsConfigurations : IConfigureOptions
{
private readonly ISiteService _siteService;

public TwilioProviderOptionsConfigurations(ISiteService siteService)
{
    _siteService = siteService;
}

public void Configure(SmsProviderOptions options)
{
    var typeOptions = new SmsProviderTypeOptions(typeof(TwilioSmsProvider));

    var site = _siteService.GetSiteSettingsAsync().GetAwaiter().GetResult();
    var settings = site.As<TwilioSettings>();

    typeOptions.IsEnabled = settings.IsEnabled;

    options.TryAddProvider(TwilioSmsProvider.TechnicalName, typeOptions);
}

}所以我们要添加 阿里云短信的相关配置。 public class AliyunProviderOptionsConfigurations : IConfigureOptions
{
private readonly ISiteService _siteService;

  public AliyunProviderOptionsConfigurations(ISiteService siteService)
  {
      _siteService = siteService;
  }

  public void Configure(SmsProviderOptions options)
  {
      var typeOptions = new SmsProviderTypeOptions(typeof(TwilioSmsProvider));

      var site = _siteService.GetSiteSettingsAsync().GetAwaiter().GetResult();
      var settings = site.As<TwilioSettings>();

      typeOptions.IsEnabled = settings.IsEnabled;

      options.TryAddProvider(TwilioSmsProvider.TechnicalName, typeOptions);
  }

}添加AliyunProviderOptionsConfigurations ublic class AliyunProviderOptionsConfigurations : IConfigureOptions
{
private readonly ISiteService _siteService;

    public AliyunProviderOptionsConfigurations(ISiteService siteService)
    {
        _siteService = siteService;
    }

    public void Configure(SmsProviderOptions options)
    {
        var typeOptions = new SmsProviderTypeOptions(typeof(AliyunSmsProvider));

   
        var settings = _siteService.GetSettingsAsync<AliyunSettings>()
.GetAwaiter()
.GetResult();

        typeOptions.IsEnabled = settings.IsEnabled;

        options.TryAddProvider(AliyunSmsProvider.TechnicalName, typeOptions);
    }
}`

添加aliyunsettings 跟aliyunsmsprovider
` public class AliyunSmsProvider : ISmsProvider
{
public const string TechnicalName = "Aliyun";

 public const string ProtectorName = "Aliyun";

 private static readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions {
     PropertyNamingPolicy = SnakeCaseNamingPolicy.Instance
 };

 private readonly ISiteService _siteService;

 private readonly IDataProtectionProvider _dataProtectionProvider;

 private readonly ILogger<AliyunSmsProvider> _logger;

 private readonly IHttpClientFactory _httpClientFactory;

 protected readonly IStringLocalizer S;

 private AliyunSettings _settings;

 public LocalizedString Name => S["Aliyun"];

 public AliyunSmsProvider(ISiteService siteService, IDataProtectionProvider dataProtectionProvider, ILogger<AliyunSmsProvider> logger, IHttpClientFactory httpClientFactory, IStringLocalizer<AliyunSmsProvider> stringLocalizer)
 {
     _siteService = siteService;
     _dataProtectionProvider = dataProtectionProvider;
     _logger = logger;
     _httpClientFactory = httpClientFactory;
     S = stringLocalizer;
 }

 public async Task<SmsResult> SendAsync(SmsMessage message)
 {
     ArgumentNullException.ThrowIfNull(message, "message");
     if (string.IsNullOrEmpty(message.To)) {
         throw new ArgumentException("A phone number is required in order to send a message.");
     }

     if (string.IsNullOrEmpty(message.Body)) {
         throw new ArgumentException("A message body is required in order to send a message.");
     }

     try {
         AliyunSettings aliyunSettings = await GetSettingsAsync();

         var aliyunclient = CreateClient(aliyunSettings);
         //var response = await aliyunclient.SendSmsAsync(request);
        SendSmsRequest sendSmsRequest = new SendSmsRequest {
             PhoneNumbers = message.To,
             SignName = aliyunSettings.SignName,

TemplateCode = aliyunSettings.TemplateCode,
TemplateParam = message.Body
};
var response = await aliyunclient.SendSmsAsync(sendSmsRequest);

         if (response.StatusCode == 200) {
             return SmsResult.Success;
         } else {
             _logger.LogError("Aliyun SMS service was unable to send SMS messages. Error code: {errorCode}, message: {errorMessage}", response.StatusCode, response.Body);
             return SmsResult.Failed(S["SMS message was not send."]);
         }


     } catch (Exception ex) {
         _logger.LogError(ex, "Twilio service was unable to send SMS messages.");
         return SmsResult.Failed(S["SMS message was not send. Error: {0}", new object[1] { ex.Message }]);
     }
   //  return SmsResult.Failed(S["SMS message was not send. Error: {0}", new object[1] { "未配置" }]);

 }
 /// <summary>
 /// 返回请求客户端 根据具体的实现
 /// </summary>
 /// <param name="settings"></param>
 /// <returns></returns>
 private HttpClient GetHttpClient(AliyunSettings settings)
 {
     string s = settings.AccessKeyId + ":" + settings.AccessKeySecret;
     string parameter = Convert.ToBase64String(Encoding.ASCII.GetBytes(s));
     HttpClient httpClient = _httpClientFactory.CreateClient("Aliyun");
     httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", parameter);
     return httpClient;
 }
 public static  Client CreateClient(AliyunSettings settings)
 {
     // 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。
     // 建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378671.html。
     AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config {
         // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
         AccessKeyId = settings.AccessKeyId,
         // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
         AccessKeySecret = settings.AccessKeySecret,
     };
     // Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi
     config.Endpoint = "dysmsapi.aliyuncs.com";
     return new AlibabaCloud.SDK.Dysmsapi20170525.Client(config);
 }
 /// <summary>
 /// 获取设置
 /// </summary>
 /// <returns></returns>
 private async Task<AliyunSettings> GetSettingsAsync()
 {
     if (_settings == null) {
         AliyunSettings aliyunSettings = await _siteService.GetSettingsAsync<AliyunSettings>();
         IDataProtector protector = _dataProtectionProvider.CreateProtector("Aliyun");
         _settings = new AliyunSettings {
             AccessKeyId = aliyunSettings.AccessKeyId,
             AccessKeySecret = aliyunSettings.AccessKeySecret,
             SignName = aliyunSettings.SignName,
             TemplateCode=   aliyunSettings.TemplateCode,
         };
     }

     return _settings;
 }

}对应添加 driver 还有视图 public class AliyunSettingsDisplayDriver : SiteDisplayDriver
{
private readonly IShellReleaseManager _shellReleaseManager;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IAuthorizationService _authorizationService;
private readonly IPhoneFormatValidator _phoneFormatValidator;
private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly INotifier _notifier;

  internal readonly IHtmlLocalizer H;
  internal readonly IStringLocalizer S;

  protected override string SettingsGroupId
      => SmsSettings.GroupId;

  public AliyunSettingsDisplayDriver(
      IShellReleaseManager shellReleaseManager,
      IHttpContextAccessor httpContextAccessor,
      IAuthorizationService authorizationService,
      IPhoneFormatValidator phoneFormatValidator,
      IDataProtectionProvider dataProtectionProvider,
      INotifier notifier,
      IHtmlLocalizer<AliyunSettingsDisplayDriver> htmlLocalizer,
      IStringLocalizer<AliyunSettingsDisplayDriver> stringLocalizer)
  {
      _shellReleaseManager = shellReleaseManager;
      _httpContextAccessor = httpContextAccessor;
      _authorizationService = authorizationService;
      _phoneFormatValidator = phoneFormatValidator;
      _dataProtectionProvider = dataProtectionProvider;
      _notifier = notifier;
      H = htmlLocalizer;
      S = stringLocalizer;
  }

  public override IDisplayResult Edit(ISite site, AliyunSettings settings, BuildEditorContext c)
  {
      return Initialize<AliyunSettingsViewModel>("AliyunSettings_Edit", model => {
          model.IsEnabled = settings.IsEnabled;
          model.AccessKeyId = settings.AccessKeyId;
          model.AccessKeySecret = settings.AccessKeySecret;
          model.SignName = settings.SignName;
          model.TemplateCode = settings.TemplateCode;
      }).Location("Content:5#Aliyun")
      .RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, SmsPermissions.ManageSmsSettings))
      .OnGroup(SettingsGroupId);
  }

  public override async Task<IDisplayResult> UpdateAsync(ISite site, AliyunSettings settings, UpdateEditorContext context)
  {
      var user = _httpContextAccessor.HttpContext?.User;

      if (!await _authorizationService.AuthorizeAsync(user, SmsPermissions.ManageSmsSettings)) {
          return null;
      }

      var model = new AliyunSettingsViewModel();

      await context.Updater.TryUpdateModelAsync(model, Prefix);
      var hasChanges = settings.IsEnabled != model.IsEnabled;
      var smsSettings = site.As<SmsSettings>();

      if (!model.IsEnabled) {
          if (hasChanges && smsSettings.DefaultProviderName == TwilioSmsProvider.TechnicalName) {
              await _notifier.WarningAsync(H["You have successfully disabled the default SMS provider. The SMS service is now disable and will remain disabled until you designate a new default provider."]);

              smsSettings.DefaultProviderName = null;

              site.Put(smsSettings);
          }

          settings.IsEnabled = false;
      } else {
          settings.IsEnabled = true;

          if (string.IsNullOrWhiteSpace(model.AccessKeyId)) {
              context.Updater.ModelState.AddModelError(Prefix, nameof(model.AccessKeyId), S["accessKeyId requires a value."]);
          }

          if (string.IsNullOrWhiteSpace(model.AccessKeySecret)) {
              context.Updater.ModelState.AddModelError(Prefix, nameof(model.AccessKeySecret), S["AccessKeySecret requires a value."]);
          }

          if (settings.SignName == null && string.IsNullOrWhiteSpace(model.SignName)) {
              context.Updater.ModelState.AddModelError(Prefix, nameof(model.SignName), S["SignName required a value."]);
          }
         
          // Has change should be evaluated before updating the value.
          hasChanges |= settings.AccessKeyId != model.AccessKeyId;
          hasChanges |= settings.AccessKeySecret != model.AccessKeySecret;
          hasChanges |= settings.SignName != model.SignName;
          hasChanges |= settings.TemplateCode != model.TemplateCode;

          settings.AccessKeyId = model.AccessKeyId;
          settings.AccessKeySecret = model.AccessKeySecret;
          settings.SignName = model.SignName;
          settings.TemplateCode = model.TemplateCode;

      }

      if (context.Updater.ModelState.IsValid && settings.IsEnabled && string.IsNullOrEmpty(smsSettings.DefaultProviderName)) {
          // If we are enabling the only provider, set it as the default one.
          smsSettings.DefaultProviderName = AliyunSmsProvider.TechnicalName;
          site.Put(smsSettings);
          hasChanges = true;
      }

      if (hasChanges) {
          _shellReleaseManager.RequestRelease();
      }

      return Edit(site, settings, context);
  }

}`

`@using OrchardCore.Sms.Services
@using OrchardCore.Sms.ViewModels
@using OrchardCore.Sms
@using Super.Aliyun.SMS.ViewModels

@model AliyunSettingsViewModel

<h4>@T["Aliyun Account Info"]</h4>
<div class="mb-3" asp-validation-class-for="AccessKeyId">
    <label asp-for="AccessKeyId" class="form-label">@T["AccessKeyId"]</label>
    <input asp-for="AccessKeyId" class="form-control" />
    <span asp-validation-for="AccessKeyId"></span>
    <span class="hint">@T["AccessKeyId must include a country code."]</span>
</div>

<div class="mb-3" asp-validation-class-for="AccessKeySecret">
    <label asp-for="AccessKeySecret" class="form-label">@T["AccessKeySecret"]</label>
    <input asp-for="AccessKeySecret" class="form-control" />
    <span asp-validation-for="AccessKeySecret"></span>
    <span class="hint">@T["AccessKeySecret must include a country code."]</span>
</div>
<div class="mb-3" asp-validation-class-for="SignName">
    <label asp-for="SignName" class="form-label">@T["SignName"]</label>
    <input asp-for="SignName" class="form-control" />
    <span asp-validation-for="SignName"></span>
</div>
<div class="mb-3" asp-validation-class-for="TemplateCode">
    <label asp-for="TemplateCode" class="form-label">@T["TemplateCode"]</label>
    <input asp-for="TemplateCode" class="form-control" />
    <span asp-validation-for="TemplateCode"></span>
</div>
`

修改starup.cs 添加
` public override void ConfigureServices(IServiceCollection services)
{

 services.AddSmsProvider<AliyunSmsProvider>("Aliyun");
 services.AddSmsProviderOptionsConfiguration<AliyunProviderOptionsConfigurations>()
     .AddSiteDisplayDriver<AliyunSettingsDisplayDriver>();            ;

}`
web项目添加引用, 然后运行 添加功能


配置下双重验证。
在用户注册的时候 就会要求填写验证码

第一次的时候 会贴心的提供恢复码

posted on 2024-10-17 09:04  刹那的菜鸟  阅读(4)  评论(0编辑  收藏  举报