Skip to content

Commit

Permalink
Merge pull request #1132 from colinin/user-avatar-provider
Browse files Browse the repository at this point in the history
feat(account): 增加用户头像变更接口
  • Loading branch information
colinin authored Mar 5, 2025
2 parents 080efff + 9c96fca commit d14f2ba
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,15 @@
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;
Expand All @@ -41,8 +38,7 @@ public class MyProfileAppService : AccountApplicationServiceBase, IMyProfileAppS

protected IIdentitySessionManager IdentitySessionManager => LazyServiceProvider.LazyGetRequiredService<IIdentitySessionManager>();
protected IIdentitySessionRepository IdentitySessionRepository => LazyServiceProvider.LazyGetRequiredService<IIdentitySessionRepository>();

protected IBlobContainer<AccountContainer> AccountBlobContainer => LazyServiceProvider.LazyGetRequiredService<IBlobContainer<AccountContainer>>();
protected IUserPictureProvider UserPictureProvider => LazyServiceProvider.LazyGetRequiredService<IUserPictureProvider>();

public MyProfileAppService(
Identity.IIdentityUserRepository userRepository,
Expand All @@ -63,57 +59,16 @@ 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 UserPictureProvider.SetPictureAsync(user, input.File.GetStream(), pictureId);

await CurrentUnitOfWork.SaveChangesAsync();
}

public async virtual Task<IRemoteStreamContent> 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");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,11 @@ public async Task<QrCodeUserInfoResult> ScanCodeAsync(string key)
{
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
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Volo.Abp.Identity.Domain" />
<ProjectReference Include="..\LINGYUN.Abp.Identity.Domain\LINGYUN.Abp.Identity.Domain.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -14,16 +15,19 @@ public class QrCodeLoginProvider : IQrCodeLoginProvider, ITransientDependency
{
protected IdentityUserManager UserManager { get; }
protected IStringLocalizer<IdentityResource> L { get; }
protected IUserPictureProvider UserPicturePovider { get; }
protected IDistributedCache<QrCodeCacheItem> QrCodeCache { get; }

public QrCodeLoginProvider(
IStringLocalizer<IdentityResource> stringLocalizer,
IDistributedCache<QrCodeCacheItem> qrCodeCache,
IUserPictureProvider userPicturePovider,
IdentityUserManager userManager)
{
L = stringLocalizer;
QrCodeCache = qrCodeCache;
UserManager = userManager;
UserPicturePovider = userPicturePovider;
}

public async virtual Task<QrCodeInfo> GenerateAsync()
Expand Down Expand Up @@ -74,10 +78,19 @@ public async virtual Task<QrCodeInfo> ScanCodeAsync(string key, QrCodeScanParams

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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

0 comments on commit d14f2ba

Please sign in to comment.