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 ab1712f4a..cf6500bd8 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,18 +7,15 @@ 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; @@ -41,8 +38,7 @@ public class MyProfileAppService : AccountApplicationServiceBase, IMyProfileAppS protected IIdentitySessionManager IdentitySessionManager => LazyServiceProvider.LazyGetRequiredService(); protected IIdentitySessionRepository IdentitySessionRepository => LazyServiceProvider.LazyGetRequiredService(); - - protected IBlobContainer AccountBlobContainer => LazyServiceProvider.LazyGetRequiredService>(); + protected IUserPictureProvider UserPictureProvider => LazyServiceProvider.LazyGetRequiredService(); public MyProfileAppService( Identity.IIdentityUserRepository userRepository, @@ -63,57 +59,16 @@ public class MyProfileAppService : AccountApplicationServiceBase, IMyProfileAppS 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 UserPictureProvider.SetPictureAsync(user, input.File.GetStream(), pictureId); 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 userId = CurrentUser.GetId().ToString("N"); - var stream = await AccountBlobContainer.GetOrNullAsync(pictureName); + var stream = await UserPictureProvider.GetPictureAsync(userId); return new RemoteStreamContent(stream, contentType: "image/jpeg"); } diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/UserProfilePictureProvider.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/UserProfilePictureProvider.cs new file mode 100644 index 000000000..20bd32dc9 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/UserProfilePictureProvider.cs @@ -0,0 +1,99 @@ +using LINGYUN.Abp.Identity; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.IO; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Volo.Abp.BlobStoring; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; +using Volo.Abp.Identity; +using Volo.Abp.Security.Claims; + +namespace LINGYUN.Abp.Account; + +[Dependency(ServiceLifetime.Transient, ReplaceServices = true)] +[ExposeServices(typeof(IUserPictureProvider))] +public class UserProfileUserPictureProvider : IUserPictureProvider +{ + protected IGuidGenerator GuidGenerator { get; } + protected IdentityUserManager UserManager { get; } + protected IBlobContainer AccountBlobContainer { get; } + public UserProfileUserPictureProvider( + IGuidGenerator guidGenerator, + IdentityUserManager userManager, + IBlobContainer accountBlobContainer) + { + UserManager = userManager; + GuidGenerator = guidGenerator; + AccountBlobContainer = accountBlobContainer; + } + + public async virtual Task SetPictureAsync(IdentityUser user, Stream stream, string fileName = null) + { + var userId = user.Id.ToString("N"); + var pictureBlobId = 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, pictureBlobId)); + + (await UserManager.UpdateAsync(user)).CheckErrors(); + + var pictureName = $"{userId}/avatar/{pictureBlobId}"; + + await AccountBlobContainer.SaveAsync(pictureName, stream, true); + } + + public async virtual Task GetPictureAsync(string userId) + { + var user = await UserManager.FindByIdAsync(userId); + if (user == null) + { + return Stream.Null; + } + + var picture = user.Claims + .FirstOrDefault(x => x.ClaimType == AbpClaimTypes.Picture) + ?.ClaimValue; + + if (picture.IsNullOrWhiteSpace()) + { + return Stream.Null; + } + + var pictureName = $"{user.Id:N}/avatar/{picture}"; + + return await AccountBlobContainer.ExistsAsync(pictureName) + ? await AccountBlobContainer.GetAsync(pictureName) + : Stream.Null; + } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/QrCodeLoginController.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/QrCodeLoginController.cs index d3667cf79..0da0ec8b6 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/QrCodeLoginController.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/QrCodeLoginController.cs @@ -68,12 +68,11 @@ public class QrCodeLoginController : AbpControllerBase { var currentUser = await _userManager.GetByIdAsync(CurrentUser.GetId()); - var picture = CurrentUser.FindClaim(AbpClaimTypes.Picture)?.Value; var userName = CurrentUser.FindClaim(AbpClaimTypes.Name)?.Value ?? currentUser.UserName; var userId = await _userManager.GetUserIdAsync(currentUser); var qrCodeInfo = await _qrCodeLoginProvider.ScanCodeAsync(key, - new QrCodeScanParams(userId, userName, picture, currentUser.TenantId)); + new QrCodeScanParams(userId, userName, currentUser.TenantId)); return new QrCodeUserInfoResult { diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/DefaultUserPictureProvider.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/DefaultUserPictureProvider.cs new file mode 100644 index 000000000..9f12bdf22 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/DefaultUserPictureProvider.cs @@ -0,0 +1,20 @@ +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; + +namespace LINGYUN.Abp.Identity; + +[Dependency(TryRegister = true)] +public class DefaultUserPictureProvider : IUserPictureProvider, ISingletonDependency +{ + public Task SetPictureAsync(IdentityUser user, Stream stream, string fileName = null) + { + return Task.CompletedTask; + } + + public Task GetPictureAsync(string userId) + { + return Task.FromResult(Stream.Null); + } +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IUserPictureProvider.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IUserPictureProvider.cs new file mode 100644 index 000000000..ab98dbab6 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IUserPictureProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.Identity; + +namespace LINGYUN.Abp.Identity; + +public interface IUserPictureProvider +{ + Task SetPictureAsync(IdentityUser user, Stream stream, string fileName = null); + + Task GetPictureAsync(string userId); +} diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN.Abp.Identity.QrCode.csproj b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN.Abp.Identity.QrCode.csproj index 814628966..d9452935f 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN.Abp.Identity.QrCode.csproj +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN.Abp.Identity.QrCode.csproj @@ -19,7 +19,7 @@ - + diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/AbpIdentityQrCodeModule.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/AbpIdentityQrCodeModule.cs index 0a53421af..7af3e517c 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/AbpIdentityQrCodeModule.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/AbpIdentityQrCodeModule.cs @@ -1,5 +1,4 @@ -using Volo.Abp.Identity; -using Volo.Abp.Identity.Localization; +using Volo.Abp.Identity.Localization; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeLoginProvider.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeLoginProvider.cs index c9fdd7297..f88d2d86c 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeLoginProvider.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeLoginProvider.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Localization; using System; +using System.IO; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Caching; @@ -14,16 +15,19 @@ public class QrCodeLoginProvider : IQrCodeLoginProvider, ITransientDependency { protected IdentityUserManager UserManager { get; } protected IStringLocalizer L { get; } + protected IUserPictureProvider UserPicturePovider { get; } protected IDistributedCache QrCodeCache { get; } public QrCodeLoginProvider( IStringLocalizer stringLocalizer, IDistributedCache qrCodeCache, + IUserPictureProvider userPicturePovider, IdentityUserManager userManager) { L = stringLocalizer; QrCodeCache = qrCodeCache; UserManager = userManager; + UserPicturePovider = userPicturePovider; } public async virtual Task GenerateAsync() @@ -74,10 +78,19 @@ public class QrCodeLoginProvider : IQrCodeLoginProvider, ITransientDependency cacheItem.UserId = @params.UserId; cacheItem.UserName = @params.UserName; - cacheItem.Picture = @params.Picture; cacheItem.TenantId = @params.TenantId; cacheItem.Status = QrCodeStatus.Scaned; + if (!@params.UserId.IsNullOrWhiteSpace()) + { + using var pictureStream = await UserPicturePovider.GetPictureAsync(@params.UserId); + if (pictureStream != Stream.Null) + { + var fileBytes = await pictureStream.GetAllBytesAsync(); + cacheItem.Picture = $"data:img/jpg;base64,{Convert.ToBase64String(fileBytes)}"; + } + } + await QrCodeCache.SetAsync(key, cacheItem, new DistributedCacheEntryOptions { diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeScanParams.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeScanParams.cs index 1c4837c1e..5e48d0d06 100644 --- a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeScanParams.cs +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeScanParams.cs @@ -6,17 +6,14 @@ public class QrCodeScanParams { public string UserId { get; } public string UserName { get; } - public string Picture { get; } public Guid? TenantId { get; } public QrCodeScanParams( string userId, string userName, - string picture = null, Guid? tenantId = null) { UserId = userId; UserName = userName; - Picture = picture; TenantId = tenantId; } }