diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/ChangePictureInput.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/ChangePictureInput.cs
new file mode 100644
index 000000000..0e68e4efd
--- /dev/null
+++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/ChangePictureInput.cs
@@ -0,0 +1,10 @@
+using Volo.Abp.Auditing;
+using Volo.Abp.Content;
+
+namespace LINGYUN.Abp.Account;
+
+public class ChangePictureInput
+{
+ [DisableAuditing]
+ public IRemoteStreamContent File { get; set; }
+}
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IAccountAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IAccountAppService.cs
index 2ebe2b1ea..be0514b46 100644
--- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IAccountAppService.cs
+++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IAccountAppService.cs
@@ -1,58 +1,58 @@
-using System.Threading.Tasks;
+using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
-using Volo.Abp.Application.Services;
-
-namespace LINGYUN.Abp.Account;
-
-public interface IAccountAppService : IApplicationService
-{
- ///
- /// 通过手机号注册用户账户
- ///
- ///
- ///
- Task RegisterAsync(PhoneRegisterDto input);
- ///
- /// 通过微信小程序注册用户账户
- ///
- ///
- ///
- Task RegisterAsync(WeChatRegisterDto input);
- ///
- /// 通过手机号重置用户密码
- ///
- ///
- ///
- Task ResetPasswordAsync(PhoneResetPasswordDto input);
- ///
- /// 发送手机注册验证码短信
- ///
- ///
- ///
- Task SendPhoneRegisterCodeAsync(SendPhoneRegisterCodeDto input);
- ///
- /// 发送手机登录验证码短信
- ///
- ///
- ///
- Task SendPhoneSigninCodeAsync(SendPhoneSigninCodeDto input);
+using Volo.Abp.Application.Services;
+
+namespace LINGYUN.Abp.Account;
+
+public interface IAccountAppService : IApplicationService
+{
+ ///
+ /// 通过手机号注册用户账户
+ ///
+ ///
+ ///
+ Task RegisterAsync(PhoneRegisterDto input);
+ ///
+ /// 通过微信小程序注册用户账户
+ ///
+ ///
+ ///
+ Task RegisterAsync(WeChatRegisterDto input);
+ ///
+ /// 通过手机号重置用户密码
+ ///
+ ///
+ ///
+ Task ResetPasswordAsync(PhoneResetPasswordDto input);
+ ///
+ /// 发送手机注册验证码短信
+ ///
+ ///
+ ///
+ Task SendPhoneRegisterCodeAsync(SendPhoneRegisterCodeDto input);
+ ///
+ /// 发送手机登录验证码短信
+ ///
+ ///
+ ///
+ Task SendPhoneSigninCodeAsync(SendPhoneSigninCodeDto input);
///
/// 发送邮件登录验证码
///
///
- ///
- Task SendEmailSigninCodeAsync(SendEmailSigninCodeDto input);
- ///
- /// 发送手机重置密码验证码短信
- ///
- ///
- ///
- Task SendPhoneResetPasswordCodeAsync(SendPhoneResetPasswordCodeDto input);
+ ///
+ Task SendEmailSigninCodeAsync(SendEmailSigninCodeDto input);
+ ///
+ /// 发送手机重置密码验证码短信
+ ///
+ ///
+ ///
+ Task SendPhoneResetPasswordCodeAsync(SendPhoneResetPasswordCodeDto input);
///
/// 获取用户二次认证提供者列表
///
///
- ///
- Task> GetTwoFactorProvidersAsync(GetTwoFactorProvidersInput input);
-}
+ ///
+ Task> GetTwoFactorProvidersAsync(GetTwoFactorProvidersInput input);
+}
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyClaimAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyClaimAppService.cs
index 5706195b3..d4efa8a6d 100644
--- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyClaimAppService.cs
+++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyClaimAppService.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System;
+using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.Account;
@@ -10,6 +11,7 @@ public interface IMyClaimAppService : IApplicationService
///
///
///
+ [Obsolete("请使用 IMyProfileAppService.ChangePictureAsync")]
Task ChangeAvatarAsync(ChangeAvatarInput input);
///
/// 查询绑定状态
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyProfileAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyProfileAppService.cs
index 430090099..05f39b352 100644
--- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyProfileAppService.cs
+++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyProfileAppService.cs
@@ -1,7 +1,9 @@
using LINGYUN.Abp.Identity;
+using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
+using Volo.Abp.Content;
namespace LINGYUN.Abp.Account;
@@ -73,4 +75,14 @@ public interface IMyProfileAppService : IApplicationService
///
///
Task ConfirmEmailAsync(ConfirmEmailInput input);
+ ///
+ /// 变更用户头像
+ ///
+ ///
+ Task ChangePictureAsync(ChangePictureInput input);
+ ///
+ /// 获取用户头像
+ ///
+ ///
+ Task GetPictureAsync();
}
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN.Abp.Account.Application.csproj b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN.Abp.Account.Application.csproj
index 1ada339df..eda58b75f 100644
--- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN.Abp.Account.Application.csproj
+++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN.Abp.Account.Application.csproj
@@ -15,6 +15,7 @@
+
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs
index 5544d58be..f5590e8f8 100644
--- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs
+++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AbpAccountApplicationModule.cs
@@ -5,6 +5,7 @@ using LINGYUN.Abp.WeChat.MiniProgram;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Account.Localization;
using Volo.Abp.AutoMapper;
+using Volo.Abp.BlobStoring;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.UI.Navigation.Urls;
@@ -17,6 +18,7 @@ namespace LINGYUN.Abp.Account;
typeof(AbpAccountApplicationContractsModule),
typeof(AbpAccountEmailingModule),
typeof(AbpIdentityDomainModule),
+ typeof(AbpBlobStoringModule),
typeof(AbpWeChatMiniProgramModule))]
public class AbpAccountApplicationModule : AbpModule
{
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountContainer.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountContainer.cs
new file mode 100644
index 000000000..bb5295045
--- /dev/null
+++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountContainer.cs
@@ -0,0 +1,8 @@
+using Volo.Abp.BlobStoring;
+
+namespace LINGYUN.Abp.Account;
+
+[BlobContainerName("users")]
+public class AccountContainer
+{
+}
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyClaimAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyClaimAppService.cs
index 3b040a4d4..21791db40 100644
--- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyClaimAppService.cs
+++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyClaimAppService.cs
@@ -1,6 +1,7 @@
using LINGYUN.Abp.Identity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyProfileAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyProfileAppService.cs
index 42790e5b0..ab1712f4a 100644
--- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyProfileAppService.cs
+++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyProfileAppService.cs
@@ -7,17 +7,23 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using System;
+using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Net;
+using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Volo.Abp;
using Volo.Abp.Account.Localization;
using Volo.Abp.Application.Dtos;
+using Volo.Abp.BlobStoring;
using Volo.Abp.Caching;
+using Volo.Abp.Content;
using Volo.Abp.Data;
using Volo.Abp.Identity;
+using Volo.Abp.Security.Claims;
using Volo.Abp.Settings;
using Volo.Abp.Users;
using IIdentitySessionRepository = LINGYUN.Abp.Identity.IIdentitySessionRepository;
@@ -36,6 +42,8 @@ public class MyProfileAppService : AccountApplicationServiceBase, IMyProfileAppS
protected IIdentitySessionManager IdentitySessionManager => LazyServiceProvider.LazyGetRequiredService();
protected IIdentitySessionRepository IdentitySessionRepository => LazyServiceProvider.LazyGetRequiredService();
+ protected IBlobContainer AccountBlobContainer => LazyServiceProvider.LazyGetRequiredService>();
+
public MyProfileAppService(
Identity.IIdentityUserRepository userRepository,
IAccountSmsSecurityCodeSender securityCodeSender,
@@ -50,6 +58,66 @@ public class MyProfileAppService : AccountApplicationServiceBase, IMyProfileAppS
LocalizationResource = typeof(AccountResource);
}
+ public async virtual Task ChangePictureAsync(ChangePictureInput input)
+ {
+ var user = await GetCurrentUserAsync();
+ var pictureId = input.File.FileName ?? $"{GuidGenerator.Create():n}.jpg";
+
+ var avatarClaims = user.Claims.Where(x => x.ClaimType.StartsWith(AbpClaimTypes.Picture))
+ .Select(x => x.ToClaim())
+ .Skip(0)
+ .Take(3)
+ .ToList();
+ if (avatarClaims.Any())
+ {
+ // 保留最多3个头像
+ if (avatarClaims.Count >= 3)
+ {
+ user.RemoveClaim(avatarClaims.First());
+ avatarClaims.RemoveAt(0);
+ }
+
+ // 历史头像加数字标识
+ for (var index = 1; index <= avatarClaims.Count; index++)
+ {
+ var avatarClaim = avatarClaims[index - 1];
+ var findClaim = user.FindClaim(avatarClaim);
+ if (findClaim != null)
+ {
+ findClaim.SetClaim(new Claim(
+ AbpClaimTypes.Picture + index.ToString(),
+ findClaim.ClaimValue));
+ }
+ }
+ }
+
+ user.AddClaim(GuidGenerator, new Claim(AbpClaimTypes.Picture, pictureId));
+
+ (await UserManager.UpdateAsync(user)).CheckErrors();
+
+ var pictureName = $"{user.Id:n}/avatar/{pictureId}";
+
+ await AccountBlobContainer.SaveAsync(pictureName, input.File.GetStream(), true);
+
+ await CurrentUnitOfWork.SaveChangesAsync();
+ }
+
+ public async virtual Task GetPictureAsync()
+ {
+ var currentUser = await GetCurrentUserAsync();
+ var pictureCalim = currentUser.Claims.FirstOrDefault(x => x.ClaimType == AbpClaimTypes.Picture);
+ if (pictureCalim?.ClaimValue.IsNullOrWhiteSpace() == true)
+ {
+ return new RemoteStreamContent(Stream.Null);
+ }
+
+ var pictureName = $"{CurrentUser.GetId():n}/avatar/{pictureCalim.ClaimValue}";
+
+ var stream = await AccountBlobContainer.GetOrNullAsync(pictureName);
+
+ return new RemoteStreamContent(stream, contentType: "image/jpeg");
+ }
+
public async virtual Task> GetSessionsAsync(GetMySessionsInput input)
{
var user = await GetCurrentUserAsync();
diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/MyProfileController.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/MyProfileController.cs
index 90da8191f..7c261bf2b 100644
--- a/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/MyProfileController.cs
+++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/MyProfileController.cs
@@ -7,6 +7,7 @@ using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
+using Volo.Abp.Content;
namespace LINGYUN.Abp.Account;
@@ -101,4 +102,18 @@ public class MyProfileController : AbpControllerBase, IMyProfileAppService
{
return MyProfileAppService.ResetAuthenticatorAsync();
}
+
+ [HttpPost]
+ [Route("picture")]
+ public virtual Task ChangePictureAsync([FromForm] ChangePictureInput input)
+ {
+ return MyProfileAppService.ChangePictureAsync(input);
+ }
+
+ [HttpGet]
+ [Route("picture")]
+ public virtual Task GetPictureAsync()
+ {
+ return MyProfileAppService.GetPictureAsync();
+ }
}