Browse Source

feat: 添加首次修改密码和定期修改密码策略

abp/pwd
Hanpaopao 12 months ago
parent
commit
486e560ebd
  1. 8
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Application.Contracts/Users/Dtos/NeedChangePasswordOutput.cs
  2. 5
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Application.Contracts/Users/IUserAppService.cs
  3. 72
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Application/Users/UserAppService.cs
  4. 31
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain.Shared/BasicManagementConsts.cs
  5. 3
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain.Shared/BasicManagementErrorCodes.cs
  6. 15
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain.Shared/Localization/BasicManagement/en.json
  7. 13
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain.Shared/Localization/BasicManagement/zh-Hans.json
  8. 26
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain/IdentityUserClaimExtensions.cs
  9. 39
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain/Settings/BasicManagementSettingDefinitionProvider.cs
  10. 20
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain/Settings/BasicManagementSettings.cs
  11. 7
      aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.HttpApi/Systems/UserController.cs

8
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Application.Contracts/Users/Dtos/NeedChangePasswordOutput.cs

@ -0,0 +1,8 @@
namespace Lion.AbpPro.BasicManagement.Users.Dtos;
public class NeedChangePasswordOutput
{
public bool NeedChangePassword { get; set; }
public string Message { get; set; }
}

5
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Application.Contracts/Users/IUserAppService.cs

@ -67,5 +67,10 @@ namespace Lion.AbpPro.BasicManagement.Users
/// 获取个人信息
/// </summary>
Task<MyProfileOutput> MyProfileAsync();
/// <summary>
/// 是否需要修改密码
/// </summary>
Task<NeedChangePasswordOutput> NeedChangePasswordAsync();
}
}

72
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Application/Users/UserAppService.cs

@ -1,3 +1,4 @@
using System.Security.Claims;
using Lion.AbpPro.BasicManagement.Users.Dtos;
using Magicodes.ExporterAndImporter.Excel;
using Magicodes.ExporterAndImporter.Excel.AspNetCore;
@ -7,6 +8,7 @@ using Volo.Abp.Account;
using Volo.Abp.Auditing;
using Volo.Abp.Uow;
using IdentityRole = Volo.Abp.Identity.IdentityRole;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
namespace Lion.AbpPro.BasicManagement.Users
{
@ -18,19 +20,21 @@ namespace Lion.AbpPro.BasicManagement.Users
private readonly IIdentityUserRepository _identityUserRepository;
private readonly IExcelExporter _excelExporter;
private readonly IOptions<IdentityOptions> _options;
private readonly ISettingProvider _settingProvider;
public UserAppService(
IIdentityUserAppService identityUserAppService,
IdentityUserManager userManager,
IIdentityUserRepository userRepository,
IExcelExporter excelExporter,
IOptions<IdentityOptions> options)
IOptions<IdentityOptions> options, ISettingProvider settingProvider)
{
_identityUserAppService = identityUserAppService;
_userManager = userManager;
_identityUserRepository = userRepository;
_excelExporter = excelExporter;
_options = options;
_settingProvider = settingProvider;
}
/// <summary>
@ -151,9 +155,35 @@ namespace Lion.AbpPro.BasicManagement.Users
result.CheckErrors();
}
await UpdateChangePasswordTimeAsync(identityUser);
return result.Succeeded;
}
private async Task UpdateChangePasswordTimeAsync(IdentityUser identityUser)
{
var now = Clock.Now.ToString("u");
var firstChangePasswordTime = identityUser.GetFirstChangePasswordTime();
if (firstChangePasswordTime == null)
{
// 用户是否第一次修改密码
await _userManager.AddClaimAsync(identityUser, new Claim(BasicManagementConsts.FirstChangePasswordTime, now));
await _userManager.AddClaimAsync(identityUser, new Claim(BasicManagementConsts.LastChangePasswordTime, now));
}
else
{
// 更新最后一次登录时间
var lastChangePasswordTimeClaim = identityUser.Claims.FirstOrDefault(e => e.ClaimType == BasicManagementConsts.LastChangePasswordTime);
if (lastChangePasswordTimeClaim != null)
{
await _userManager.ReplaceClaimAsync(identityUser, new Claim(lastChangePasswordTimeClaim.ClaimType, lastChangePasswordTimeClaim.ClaimValue), new Claim(BasicManagementConsts.LastChangePasswordTime, now));
}
else
{
await _userManager.AddClaimAsync(identityUser, new Claim(BasicManagementConsts.LastChangePasswordTime, now));
}
}
}
/// <summary>
/// 重置
/// </summary>
@ -165,6 +195,7 @@ namespace Lion.AbpPro.BasicManagement.Users
await _userManager.RemovePasswordAsync(identityUser);
var result = await _userManager.AddPasswordAsync(identityUser, input.Password);
result.CheckErrors();
await UpdateChangePasswordTimeAsync(identityUser);
return result.Succeeded;
}
@ -205,5 +236,44 @@ namespace Lion.AbpPro.BasicManagement.Users
return ObjectMapper.Map<Volo.Abp.Identity.IdentityUser, MyProfileOutput>(user);
}
public virtual async Task<NeedChangePasswordOutput> NeedChangePasswordAsync()
{
var result = new NeedChangePasswordOutput();
// 获取设置
var value = await _settingProvider.GetOrNullAsync(BasicManagementConsts.EnableNewAccountRequiredChangePassword);
bool.TryParse(value, out var convertValue);
if (!convertValue) return result;
var user = await _userManager.FindByIdAsync(CurrentUser.GetId().ToString());
if (user == null)
return result;
var firstChangePasswordTime = user.GetFirstChangePasswordTime();
if (firstChangePasswordTime == null)
{
result.NeedChangePassword = true;
result.Message = L[BasicManagementErrorCodes.NewPasswordExpire];
return result;
}
var lastChangePasswordTime = user.GetLastChangePasswordTime();
if (!lastChangePasswordTime.HasValue) return result;
// 获取过期天数
var expireDays = await _settingProvider.GetOrNullAsync(BasicManagementConsts.PasswordExpireDay);
int.TryParse(expireDays, out var expireDay);
var remindDays = await _settingProvider.GetOrNullAsync(BasicManagementConsts.PasswordRemindDay);
int.TryParse(remindDays, out var remindDay);
// 提前7天提示用户需要修改密码
var day = expireDay - remindDay;
if (lastChangePasswordTime.Value > Clock.Now.AddDays(-day)) return result;
result.NeedChangePassword = true;
result.Message = L[BasicManagementErrorCodes.OldPasswordExpire];
return result;
}
}
}

31
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain.Shared/BasicManagementConsts.cs

@ -6,4 +6,35 @@ public static class BasicManagementConsts
public const string NameSpace = "Lion.AbpPro.BasicManagement";
/// <summary>默认语言</summary>
public const string DefaultCultureName = "zh-Hans";
/// <summary>
/// 新用户首次登录是否强制修改密码
/// </summary>
public const string EnableNewAccountRequiredChangePassword = "EnableNewAccountRequiredChangePassword";
/// <summary>
/// 启用密码过期是否强制修改密码
/// </summary>
public const string EnableExpireRequiredChangePassword = "EnableExpireRequiredChangePassword";
/// <summary>
/// 密码过期天数
/// </summary>
public const string PasswordExpireDay = "PasswordExpireDay";
/// <summary>
/// 密码过期,提前通知天数
/// </summary>
public const string PasswordRemindDay = "PasswordRemindDay";
/// <summary>
/// 首次修改密码时间
/// </summary>
public const string FirstChangePasswordTime = "FirstChangePasswordTime";
/// <summary>
/// 最后修改密码时间
/// </summary>
public const string LastChangePasswordTime = "LastChangePasswordTime";
}

3
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain.Shared/BasicManagementErrorCodes.cs

@ -9,4 +9,7 @@ public static class BasicManagementErrorCodes
public const string TenantNotExist = BasicManagementConsts.NameSpace + ":100005";
public const string NotSupportSetConnectionString = BasicManagementConsts.NameSpace + ":100006";
public const string UserNotExist = BasicManagementConsts.NameSpace + ":100007";
public const string PasswordExpire = BasicManagementConsts.NameSpace + ":100008";
public const string NewPasswordExpire = BasicManagementConsts.NameSpace + ":100009";
public const string OldPasswordExpire = BasicManagementConsts.NameSpace + ":100010";
}

15
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain.Shared/Localization/BasicManagement/en.json

@ -1,7 +1,7 @@
{
"culture": "en",
"texts": {
"MyAccount": "My account",
"MyAccount": "My account",
"SamplePageMessage": "A sample page for the BasicManagement module",
"Permission:Query": "Query",
"Permission:Create": "Create",
@ -18,12 +18,23 @@
"Permission:OrganizationUnitManagement": "OrganizationUnitManagement",
"Permission:FeatureManagement": "FeatureManagement",
"Setting.Group.System": "System",
"EnableNewAccountRequiredChangePassword": "EnableNewAccountRequiredChangePassword",
"Description:EnableNewAccountRequiredChangePassword": "EnableNewAccountRequiredChangePassword",
"EnableExpireRequiredChangePassword": "EnableExpireRequiredChangePassword",
"Description:EnableExpireRequiredChangePassword": "EnableExpireRequiredChangePassword",
"PasswordExpireDay": "PasswordExpireDay",
"Description:PasswordExpireDay": "PasswordExpireDay",
"PasswordRemindDay": "PasswordRemindDay",
"Description:PasswordRemindDay": "PasswordRemindDay",
"Lion.AbpPro.BasicManagement:100001": "OrganizationUnit Not Exist",
"Lion.AbpPro.BasicManagement:100002": "UserLockedOut",
"Lion.AbpPro.BasicManagement:100003": "UserOrPasswordMismatch",
"Lion.AbpPro.BasicManagement:100004": "UserDisabled",
"Lion.AbpPro.BasicManagement:100005": "Tenant Not Exist",
"Lion.AbpPro.BasicManagement:100006": "Not Support Set ConnectionString",
"Lion.AbpPro.BasicManagement:100007": "User Not Exist"
"Lion.AbpPro.BasicManagement:100007": "User Not Exist",
"Lion.AbpPro.BasicManagement:100008": "Password Has Expire",
"Lion.AbpPro.BasicManagement:100009": "A new user must change the password upon the first login.",
"Lion.AbpPro.BasicManagement:100010": "Your password is about to expire. Please change your password."
}
}

13
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain.Shared/Localization/BasicManagement/zh-Hans.json

@ -18,12 +18,23 @@
"Permission:OrganizationUnitManagement": "组织结构管理",
"Permission:FeatureManagement": "功能管理",
"Setting.Group.System": "系统",
"EnableNewAccountRequiredChangePassword": "首次登录必须修改密码",
"Description:EnableNewAccountRequiredChangePassword": "首次登录必须修改密码",
"EnableExpireRequiredChangePassword": "定期修改密码",
"Description:EnableExpireRequiredChangePassword": "定期修改密码",
"PasswordExpireDay": "密码过期天数",
"Description:PasswordExpireDay": "密码过期天数",
"PasswordRemindDay": "密码过期提醒天数",
"Description:PasswordRemindDay": "密码过期提醒天数",
"Lion.AbpPro.BasicManagement:100001": "组织机构不存在",
"Lion.AbpPro.BasicManagement:100002": "用户被锁定",
"Lion.AbpPro.BasicManagement:100003": "用户名或者密码错误",
"Lion.AbpPro.BasicManagement:100004": "用户已禁用",
"Lion.AbpPro.BasicManagement:100005": "租户不存在",
"Lion.AbpPro.BasicManagement:100006": "当前模块不支持设置数据库连接字符串",
"Lion.AbpPro.BasicManagement:100007": "用户不存在"
"Lion.AbpPro.BasicManagement:100007": "用户不存在",
"Lion.AbpPro.BasicManagement:100008": "密码已过期,请联系管理员重置密码。",
"Lion.AbpPro.BasicManagement:100009": "新用户首次登录需要修改密码.",
"Lion.AbpPro.BasicManagement:100010": "您的密码即将过期,请修改密码."
}
}

26
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain/IdentityUserClaimExtensions.cs

@ -0,0 +1,26 @@
namespace Lion.AbpPro.BasicManagement;
public static class IdentityUserClaimExtensions
{
/// <summary>
/// 获取用户首次修改密码时间
/// </summary>
public static DateTime? GetFirstChangePasswordTime(this IdentityUser user)
{
var claim = user.Claims.FirstOrDefault(e => e.ClaimType == BasicManagementConsts.FirstChangePasswordTime);
if (claim == null) return null;
DateTime.TryParse(claim.ClaimValue, out var result);
return result;
}
/// <summary>
/// 获取用户最后一次登录时间
/// </summary>
public static DateTime? GetLastChangePasswordTime(this IdentityUser user)
{
var claim = user.Claims.FirstOrDefault(e => e.ClaimType == BasicManagementConsts.LastChangePasswordTime);
if (claim == null) return null;
DateTime.TryParse(claim.ClaimValue, out var result);
return result;
}
}

39
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain/Settings/BasicManagementSettingDefinitionProvider.cs

@ -73,6 +73,45 @@ public class BasicManagementSettingDefinitionProvider : SettingDefinitionProvide
BasicManagementSettings.Group.SystemManagement)
.WithProperty(AbpProSettingConsts.ControlType.Default,
AbpProSettingConsts.ControlType.Number);
context.Add(
new SettingDefinition(BasicManagementSettings.EnableNewAccountRequiredChangePassword,
"false",
L(BasicManagementConsts.EnableNewAccountRequiredChangePassword),
L($"Description:{BasicManagementConsts.EnableNewAccountRequiredChangePassword}"))
.WithProperty(BasicManagementSettings.Group.Default,
BasicManagementSettings.Group.SystemManagement)
.WithProperty(AbpProSettingConsts.ControlType.Default,
AbpProSettingConsts.ControlType.TypeCheckBox));
context.Add(
new SettingDefinition(BasicManagementSettings.EnableExpireRequiredChangePassword,
"false",
L(BasicManagementConsts.EnableExpireRequiredChangePassword),
L($"Description:{BasicManagementConsts.EnableExpireRequiredChangePassword}"))
.WithProperty(BasicManagementSettings.Group.Default,
BasicManagementSettings.Group.SystemManagement)
.WithProperty(AbpProSettingConsts.ControlType.Default,
AbpProSettingConsts.ControlType.TypeCheckBox));
context.Add(
new SettingDefinition(BasicManagementSettings.PasswordExpireDay,
"90",
L(BasicManagementConsts.PasswordExpireDay),
L($"Description:{BasicManagementConsts.PasswordExpireDay}"))
.WithProperty(BasicManagementSettings.Group.Default,
BasicManagementSettings.Group.SystemManagement)
.WithProperty(AbpProSettingConsts.ControlType.Default,
AbpProSettingConsts.ControlType.Number));
context.Add(
new SettingDefinition(BasicManagementSettings.PasswordRemindDay,
"7",
L(BasicManagementConsts.PasswordRemindDay),
L($"Description:{BasicManagementConsts.PasswordRemindDay}"))
.WithProperty(BasicManagementSettings.Group.Default,
BasicManagementSettings.Group.SystemManagement)
.WithProperty(AbpProSettingConsts.ControlType.Default,
AbpProSettingConsts.ControlType.Number));
}

20
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.Domain/Settings/BasicManagementSettings.cs

@ -3,6 +3,26 @@
public static class BasicManagementSettings
{
/// <summary>
/// 新用户首次登录是否强制修改密码
/// </summary>
public const string EnableNewAccountRequiredChangePassword = BasicManagementConsts.EnableNewAccountRequiredChangePassword;
/// <summary>
/// 启用密码过期是否强制修改密码
/// </summary>
public const string EnableExpireRequiredChangePassword = BasicManagementConsts.EnableExpireRequiredChangePassword;
/// <summary>
/// 定期修改密码天数默认90天
/// </summary>
public const string PasswordExpireDay = BasicManagementConsts.PasswordExpireDay;
/// <summary>
/// 密码过期,提前通知天数
/// </summary>
public const string PasswordRemindDay = BasicManagementConsts.PasswordRemindDay;
/// <summary>
/// 系统控制分组
/// </summary>

7
aspnet-core/modules/BasicManagement/src/Lion.AbpPro.BasicManagement.HttpApi/Systems/UserController.cs

@ -98,5 +98,12 @@ namespace Lion.AbpPro.BasicManagement.Systems
{
return _userAppService.MyProfileAsync();
}
[HttpPost("needChangePassword")]
[SwaggerOperation(summary: "是否需要修改密码", Tags = new[] { "Users" })]
public Task<NeedChangePasswordOutput> NeedChangePasswordAsync()
{
return _userAppService.NeedChangePasswordAsync();
}
}
}
Loading…
Cancel
Save