committed by
GitHub
28 changed files with 452 additions and 68 deletions
@ -1,13 +0,0 @@ |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Account; |
|||
|
|||
public interface IAccountSmsSecurityCodeSender |
|||
{ |
|||
Task SendSmsCodeAsync( |
|||
string phone, |
|||
string token, |
|||
string template, // 传递模板号
|
|||
CancellationToken cancellation = default); |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,29 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks> |
|||
<AssemblyName>LINGYUN.Abp.Account.Security</AssemblyName> |
|||
<PackageId>LINGYUN.Abp.Account.Security</PackageId> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Remove="LINGYUN\Abp\Account\Security\Templates\*.tpl" /> |
|||
<None Remove="LINGYUN\Abp\Account\Security\Localization\Resources\*.json" /> |
|||
<EmbeddedResource Include="LINGYUN\Abp\Account\Security\Templates\*.tpl" /> |
|||
<EmbeddedResource Include="LINGYUN\Abp\Account\Security\Localization\Resources\*.json" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Emailing" /> |
|||
<PackageReference Include="Volo.Abp.Sms" /> |
|||
<PackageReference Include="Volo.Abp.UI.Navigation" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,31 @@ |
|||
using LINGYUN.Abp.Account.Security.Localization; |
|||
using Volo.Abp.Emailing; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Sms; |
|||
using Volo.Abp.UI.Navigation; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Abp.Account.Security; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpEmailingModule), |
|||
typeof(AbpSmsModule), |
|||
typeof(AbpUiNavigationModule))] |
|||
public class AbpAccountSecurityModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpAccountSecurityModule>(); |
|||
}); |
|||
|
|||
Configure<AbpLocalizationOptions>(options => |
|||
{ |
|||
options.Resources |
|||
.Add<AccountSecurityResource>("en") |
|||
.AddVirtualJson("/LINGYUN/Abp/Account/Security/Localization/Resources"); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,135 @@ |
|||
using LINGYUN.Abp.Account.Security.Localization; |
|||
using LINGYUN.Abp.Account.Security.Templates; |
|||
using Microsoft.Extensions.Localization; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Text.Encodings.Web; |
|||
using System.Threading.Tasks; |
|||
using System.Web; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Emailing; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.TextTemplating; |
|||
using Volo.Abp.UI.Navigation.Urls; |
|||
|
|||
namespace LINGYUN.Abp.Account.Security; |
|||
|
|||
[Dependency(ReplaceServices = true)] |
|||
[ExposeServices( |
|||
typeof(IAccountEmailSecurityCodeSender), |
|||
typeof(AccountEmailSecurityCodeSender))] |
|||
public class AccountEmailSecurityCodeSender : |
|||
IAccountEmailSecurityCodeSender, |
|||
ITransientDependency |
|||
{ |
|||
protected ITemplateRenderer TemplateRenderer { get; } |
|||
protected IEmailSender EmailSender { get; } |
|||
protected IStringLocalizer<AccountSecurityResource> StringLocalizer { get; } |
|||
protected IAppUrlProvider AppUrlProvider { get; } |
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
|
|||
public AccountEmailSecurityCodeSender( |
|||
IEmailSender emailSender, |
|||
ICurrentTenant currentTenant, |
|||
IAppUrlProvider appUrlProvider, |
|||
ITemplateRenderer templateRenderer, |
|||
IStringLocalizer<AccountSecurityResource> accountLocalizer) |
|||
{ |
|||
EmailSender = emailSender; |
|||
CurrentTenant = currentTenant; |
|||
AppUrlProvider = appUrlProvider; |
|||
StringLocalizer = accountLocalizer; |
|||
TemplateRenderer = templateRenderer; |
|||
} |
|||
|
|||
public async virtual Task SendLoginCodeAsync( |
|||
string code, |
|||
string userName, |
|||
string emailAddress) |
|||
{ |
|||
var emailContent = await TemplateRenderer.RenderAsync( |
|||
AccountEmailTemplates.MailSecurityVerifyLink, |
|||
new { code = code, user = userName } |
|||
); |
|||
|
|||
await EmailSender.SendAsync( |
|||
emailAddress, |
|||
StringLocalizer["MailSecurityVerify"], |
|||
emailContent |
|||
); |
|||
} |
|||
|
|||
public async virtual Task SendConfirmLinkAsync( |
|||
Guid userId, |
|||
string userEmail, |
|||
string confirmToken, |
|||
string appName, |
|||
string returnUrl = null, |
|||
string returnUrlHash = null, |
|||
Guid? userTenantId = null) |
|||
{ |
|||
Debug.Assert(CurrentTenant.Id == userTenantId, "This method can only work for current tenant!"); |
|||
|
|||
var url = await AppUrlProvider.GetUrlAsync(appName, AccountUrlNames.EmailConfirm); |
|||
|
|||
var link = $"{url}?userId={userId}&{TenantResolverConsts.DefaultTenantKey}={userTenantId}&confirmToken={UrlEncoder.Default.Encode(confirmToken)}"; |
|||
|
|||
if (!returnUrl.IsNullOrEmpty()) |
|||
{ |
|||
link += "&returnUrl=" + NormalizeReturnUrl(returnUrl); |
|||
} |
|||
|
|||
if (!returnUrlHash.IsNullOrEmpty()) |
|||
{ |
|||
link += "&returnUrlHash=" + returnUrlHash; |
|||
} |
|||
|
|||
var emailContent = await TemplateRenderer.RenderAsync( |
|||
AccountEmailTemplates.MailConfirmLink, |
|||
new { link = link } |
|||
); |
|||
|
|||
await EmailSender.SendAsync( |
|||
userEmail, |
|||
StringLocalizer["EmailConfirm"], |
|||
emailContent |
|||
); |
|||
} |
|||
|
|||
protected virtual string NormalizeReturnUrl(string returnUrl) |
|||
{ |
|||
if (returnUrl.IsNullOrEmpty()) |
|||
{ |
|||
return returnUrl; |
|||
} |
|||
|
|||
//Handling openid connect login
|
|||
if (returnUrl.StartsWith("/connect/authorize/callback", StringComparison.OrdinalIgnoreCase)) |
|||
{ |
|||
if (returnUrl.Contains("?")) |
|||
{ |
|||
var queryPart = returnUrl.Split('?')[1]; |
|||
var queryParameters = queryPart.Split('&'); |
|||
foreach (var queryParameter in queryParameters) |
|||
{ |
|||
if (queryParameter.Contains("=")) |
|||
{ |
|||
var queryParam = queryParameter.Split('='); |
|||
if (queryParam[0] == "redirect_uri") |
|||
{ |
|||
return HttpUtility.UrlDecode(queryParam[1]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (returnUrl.StartsWith("/connect/authorize?", StringComparison.OrdinalIgnoreCase)) |
|||
{ |
|||
return HttpUtility.UrlEncode(returnUrl); |
|||
} |
|||
|
|||
return returnUrl; |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace LINGYUN.Abp.Account.Security; |
|||
|
|||
public static class AccountUrlNames |
|||
{ |
|||
public const string EmailConfirm = "Abp.Account.EmailConfirm"; |
|||
public const string EmailVerifyLogin = "Abp.Account.EmailVerifyLogin"; |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Account.Security; |
|||
/// <summary>
|
|||
/// 邮件安全码发送接口
|
|||
/// </summary>
|
|||
public interface IAccountEmailSecurityCodeSender |
|||
{ |
|||
/// <summary>
|
|||
/// 发送邮件登录验证码
|
|||
/// </summary>
|
|||
/// <param name="code">验证码</param>
|
|||
/// <param name="userName">用户名</param>
|
|||
/// <param name="emailAddress">邮件地址</param>
|
|||
/// <returns></returns>
|
|||
Task SendLoginCodeAsync( |
|||
string code, |
|||
string userName, |
|||
string emailAddress); |
|||
/// <summary>
|
|||
/// 发送邮件确认链接
|
|||
/// </summary>
|
|||
/// <param name="userId">用户Id</param>
|
|||
/// <param name="userEmail">用户邮件</param>
|
|||
/// <param name="confirmToken">确认Token</param>
|
|||
/// <param name="appName">应用名称</param>
|
|||
/// <param name="returnUrl">回调路径</param>
|
|||
/// <param name="returnUrlHash">回调路径Hash</param>
|
|||
/// <param name="userTenantId">用户租户Id</param>
|
|||
/// <returns></returns>
|
|||
Task SendConfirmLinkAsync( |
|||
Guid userId, |
|||
string userEmail, |
|||
string confirmToken, |
|||
string appName, |
|||
string returnUrl = null, |
|||
string returnUrlHash = null, |
|||
Guid? userTenantId = null |
|||
); |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace LINGYUN.Abp.Account.Security; |
|||
/// <summary>
|
|||
/// 短信安全码发送接口
|
|||
/// </summary>
|
|||
public interface IAccountSmsSecurityCodeSender |
|||
{ |
|||
/// <summary>
|
|||
/// 发送短信验证码
|
|||
/// </summary>
|
|||
/// <param name="phone">手机号</param>
|
|||
/// <param name="code">短信验证码</param>
|
|||
/// <param name="templateCode">短信验证模板</param>
|
|||
/// <param name="cancellation"></param>
|
|||
/// <returns></returns>
|
|||
Task SendAsync( |
|||
string phone, |
|||
string code, |
|||
string templateCode, |
|||
CancellationToken cancellation = default); |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace LINGYUN.Abp.Account.Security.Localization; |
|||
|
|||
[LocalizationResourceName("AbpAccountSecurity")] |
|||
public class AccountSecurityResource |
|||
{ |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
"TextTemplate:Abp.Account.MailSecurityVerifyLink": "Mail security validation template", |
|||
"TextTemplate:Abp.Account.MailConfirmLink": "Mail confirm template", |
|||
"MailSecurityVerify": "Mail security verification", |
|||
"VerifyMyEmailAddress": "Hello {0}<br/><p>Your email security verification code is as follows. Please enter the verification code to proceed to the next step.</p><p>If not operated by you, please ignore this email.</p>", |
|||
"MailSecurityVerifyRemarks": "<p>(If it is not in the form of a link, copy the address to the browser address bar for further access)</p><p>Thank you for your visit and have a good time!</p>", |
|||
"ClickToValidation": "Click link verification", |
|||
"Validation": "Validation", |
|||
"EmailConfirm": "Email confirm", |
|||
"EmailConfirmInfo": "We received an email confirmation request! If you initiated this request, please click the link below to confirm the email address.", |
|||
"ConfirmMyEmail": "Bind my email address", |
|||
"YourEmailIsSuccessfullyConfirm": "Your email address was bound successfully." |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
{ |
|||
"culture": "zh-Hans", |
|||
"texts": { |
|||
"TextTemplate:Abp.Account.MailSecurityVerifyLink": "邮件验证模板", |
|||
"TextTemplate:Abp.Account.MailConfirmLink": "邮件确认模板", |
|||
"MailSecurityVerify": "邮件安全验证", |
|||
"VerifyMyEmailAddress": "您好<br/><p>您此次邮件安全验证码如下,请输入验证码进行下一步操作。</p><p>如非你本人操作,请忽略此邮件。</p>", |
|||
"MailSecurityVerifyRemarks": "此邮件为系统所发,请勿直接回复。", |
|||
"ClickToValidation": "点击进行验证", |
|||
"Validation": "验证", |
|||
"EmailConfirm": "邮件确认", |
|||
"EmailConfirmInfo": "我们收到了邮件确认请求!如果你发起了此请求,请单击以下链接以确认邮件地址.", |
|||
"ConfirmMyEmail": "绑定我的邮箱地址", |
|||
"YourEmailIsSuccessfullyConfirm": "您的邮件地址绑定成功." |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
namespace LINGYUN.Abp.Account.Security.Templates; |
|||
|
|||
public static class AccountEmailTemplates |
|||
{ |
|||
/// <summary>
|
|||
/// 邮件地址确认
|
|||
/// </summary>
|
|||
public const string MailConfirmLink = "Abp.Account.MailConfirmLink"; |
|||
/// <summary>
|
|||
/// 邮件安全验证
|
|||
/// </summary>
|
|||
public const string MailSecurityVerifyLink = "Abp.Account.MailSecurityVerifyLink"; |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using LINGYUN.Abp.Account.Security.Localization; |
|||
using Volo.Abp.Emailing.Templates; |
|||
using Volo.Abp.Localization; |
|||
using Volo.Abp.TextTemplating; |
|||
|
|||
namespace LINGYUN.Abp.Account.Security.Templates; |
|||
|
|||
public class AccountTemplateDefinitionProvider : TemplateDefinitionProvider |
|||
{ |
|||
public override void Define(ITemplateDefinitionContext context) |
|||
{ |
|||
context.Add( |
|||
new TemplateDefinition( |
|||
AccountEmailTemplates.MailSecurityVerifyLink, |
|||
displayName: L($"TextTemplate:{AccountEmailTemplates.MailSecurityVerifyLink}"), |
|||
layout: StandardEmailTemplates.Layout, |
|||
localizationResource: typeof(AccountSecurityResource) |
|||
).WithVirtualFilePath("/LINGYUN/Abp/Account/Security/Templates/MailSecurityVerify.tpl", true), |
|||
new TemplateDefinition( |
|||
AccountEmailTemplates.MailConfirmLink, |
|||
displayName: L($"TextTemplate:{AccountEmailTemplates.MailConfirmLink}"), |
|||
layout: StandardEmailTemplates.Layout, |
|||
localizationResource: typeof(AccountSecurityResource) |
|||
).WithVirtualFilePath("/LINGYUN/Abp/Account/Security/Templates/MailConfirm.tpl", true) |
|||
); |
|||
} |
|||
|
|||
private static ILocalizableString L(string name) |
|||
{ |
|||
return LocalizableString.Create<AccountSecurityResource>(name); |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
<h3>{{L "EmailConfirm"}}</h3> |
|||
|
|||
<p>{{L "EmailConfirmInfo"}}</p> |
|||
|
|||
<div> |
|||
<a href="{{model.link}}">{{L "ConfirmMyEmail"}}</a> |
|||
</div> |
|||
@ -0,0 +1,5 @@ |
|||
<div style="position: absolute;"> |
|||
<span>{{L "VerifyMyEmailAddress"}}{{model.user}}</span> |
|||
<p style="display:block; padding:0 50px; width: 150px; height:48px; line-height:48px; color:#cc0000; font-size:26px; background:#9c9797; font-weight:bold;">{{model.code}}</p> |
|||
<span>{{L "MailSecurityVerifyRemarks"}}</span> |
|||
</div> |
|||
Loading…
Reference in new issue