Browse Source

feat(account): 增加用户头像变更接口

pull/1132/head
colin 1 year ago
parent
commit
9c96fca63a
  1. 53
      aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyProfileAppService.cs
  2. 99
      aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/UserProfilePictureProvider.cs
  3. 3
      aspnet-core/modules/account/LINGYUN.Abp.Account.Web/Areas/Account/Controllers/QrCodeLoginController.cs
  4. 20
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/DefaultUserPictureProvider.cs
  5. 13
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain/LINGYUN/Abp/Identity/IUserPictureProvider.cs
  6. 2
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN.Abp.Identity.QrCode.csproj
  7. 3
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/AbpIdentityQrCodeModule.cs
  8. 15
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeLoginProvider.cs
  9. 3
      aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN/Abp/Identity/QrCode/QrCodeScanParams.cs

53
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.Caching.Distributed;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Security.Claims;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Account.Localization; using Volo.Abp.Account.Localization;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.BlobStoring;
using Volo.Abp.Caching; using Volo.Abp.Caching;
using Volo.Abp.Content; using Volo.Abp.Content;
using Volo.Abp.Data; using Volo.Abp.Data;
@ -41,8 +38,7 @@ public class MyProfileAppService : AccountApplicationServiceBase, IMyProfileAppS
protected IIdentitySessionManager IdentitySessionManager => LazyServiceProvider.LazyGetRequiredService<IIdentitySessionManager>(); protected IIdentitySessionManager IdentitySessionManager => LazyServiceProvider.LazyGetRequiredService<IIdentitySessionManager>();
protected IIdentitySessionRepository IdentitySessionRepository => LazyServiceProvider.LazyGetRequiredService<IIdentitySessionRepository>(); protected IIdentitySessionRepository IdentitySessionRepository => LazyServiceProvider.LazyGetRequiredService<IIdentitySessionRepository>();
protected IUserPictureProvider UserPictureProvider => LazyServiceProvider.LazyGetRequiredService<IUserPictureProvider>();
protected IBlobContainer<AccountContainer> AccountBlobContainer => LazyServiceProvider.LazyGetRequiredService<IBlobContainer<AccountContainer>>();
public MyProfileAppService( public MyProfileAppService(
Identity.IIdentityUserRepository userRepository, Identity.IIdentityUserRepository userRepository,
@ -63,57 +59,16 @@ public class MyProfileAppService : AccountApplicationServiceBase, IMyProfileAppS
var user = await GetCurrentUserAsync(); var user = await GetCurrentUserAsync();
var pictureId = input.File.FileName ?? $"{GuidGenerator.Create():n}.jpg"; var pictureId = input.File.FileName ?? $"{GuidGenerator.Create():n}.jpg";
var avatarClaims = user.Claims.Where(x => x.ClaimType.StartsWith(AbpClaimTypes.Picture)) await UserPictureProvider.SetPictureAsync(user, input.File.GetStream(), pictureId);
.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(); await CurrentUnitOfWork.SaveChangesAsync();
} }
public async virtual Task<IRemoteStreamContent> GetPictureAsync() public async virtual Task<IRemoteStreamContent> GetPictureAsync()
{ {
var currentUser = await GetCurrentUserAsync(); var userId = CurrentUser.GetId().ToString("N");
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); var stream = await UserPictureProvider.GetPictureAsync(userId);
return new RemoteStreamContent(stream, contentType: "image/jpeg"); return new RemoteStreamContent(stream, contentType: "image/jpeg");
} }

99
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<AccountContainer> AccountBlobContainer { get; }
public UserProfileUserPictureProvider(
IGuidGenerator guidGenerator,
IdentityUserManager userManager,
IBlobContainer<AccountContainer> 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<Stream> 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;
}
}

3
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 currentUser = await _userManager.GetByIdAsync(CurrentUser.GetId());
var picture = CurrentUser.FindClaim(AbpClaimTypes.Picture)?.Value;
var userName = CurrentUser.FindClaim(AbpClaimTypes.Name)?.Value ?? currentUser.UserName; var userName = CurrentUser.FindClaim(AbpClaimTypes.Name)?.Value ?? currentUser.UserName;
var userId = await _userManager.GetUserIdAsync(currentUser); var userId = await _userManager.GetUserIdAsync(currentUser);
var qrCodeInfo = await _qrCodeLoginProvider.ScanCodeAsync(key, var qrCodeInfo = await _qrCodeLoginProvider.ScanCodeAsync(key,
new QrCodeScanParams(userId, userName, picture, currentUser.TenantId)); new QrCodeScanParams(userId, userName, currentUser.TenantId));
return new QrCodeUserInfoResult return new QrCodeUserInfoResult
{ {

20
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<Stream> GetPictureAsync(string userId)
{
return Task.FromResult(Stream.Null);
}
}

13
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<Stream> GetPictureAsync(string userId);
}

2
aspnet-core/modules/identity/LINGYUN.Abp.Identity.QrCode/LINGYUN.Abp.Identity.QrCode.csproj

@ -19,7 +19,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Volo.Abp.Identity.Domain" /> <ProjectReference Include="..\LINGYUN.Abp.Identity.Domain\LINGYUN.Abp.Identity.Domain.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

3
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.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;

15
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.Caching.Distributed;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using System; using System;
using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Caching; using Volo.Abp.Caching;
@ -14,16 +15,19 @@ public class QrCodeLoginProvider : IQrCodeLoginProvider, ITransientDependency
{ {
protected IdentityUserManager UserManager { get; } protected IdentityUserManager UserManager { get; }
protected IStringLocalizer<IdentityResource> L { get; } protected IStringLocalizer<IdentityResource> L { get; }
protected IUserPictureProvider UserPicturePovider { get; }
protected IDistributedCache<QrCodeCacheItem> QrCodeCache { get; } protected IDistributedCache<QrCodeCacheItem> QrCodeCache { get; }
public QrCodeLoginProvider( public QrCodeLoginProvider(
IStringLocalizer<IdentityResource> stringLocalizer, IStringLocalizer<IdentityResource> stringLocalizer,
IDistributedCache<QrCodeCacheItem> qrCodeCache, IDistributedCache<QrCodeCacheItem> qrCodeCache,
IUserPictureProvider userPicturePovider,
IdentityUserManager userManager) IdentityUserManager userManager)
{ {
L = stringLocalizer; L = stringLocalizer;
QrCodeCache = qrCodeCache; QrCodeCache = qrCodeCache;
UserManager = userManager; UserManager = userManager;
UserPicturePovider = userPicturePovider;
} }
public async virtual Task<QrCodeInfo> GenerateAsync() public async virtual Task<QrCodeInfo> GenerateAsync()
@ -74,10 +78,19 @@ public class QrCodeLoginProvider : IQrCodeLoginProvider, ITransientDependency
cacheItem.UserId = @params.UserId; cacheItem.UserId = @params.UserId;
cacheItem.UserName = @params.UserName; cacheItem.UserName = @params.UserName;
cacheItem.Picture = @params.Picture;
cacheItem.TenantId = @params.TenantId; cacheItem.TenantId = @params.TenantId;
cacheItem.Status = QrCodeStatus.Scaned; 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, await QrCodeCache.SetAsync(key, cacheItem,
new DistributedCacheEntryOptions new DistributedCacheEntryOptions
{ {

3
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 UserId { get; }
public string UserName { get; } public string UserName { get; }
public string Picture { get; }
public Guid? TenantId { get; } public Guid? TenantId { get; }
public QrCodeScanParams( public QrCodeScanParams(
string userId, string userId,
string userName, string userName,
string picture = null,
Guid? tenantId = null) Guid? tenantId = null)
{ {
UserId = userId; UserId = userId;
UserName = userName; UserName = userName;
Picture = picture;
TenantId = tenantId; TenantId = tenantId;
} }
} }

Loading…
Cancel
Save