Browse Source

Merge pull request #1132 from colinin/user-avatar-provider

feat(account): 增加用户头像变更接口
pull/1149/head
yx lin 1 year ago
committed by GitHub
parent
commit
d14f2ba252
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  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.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<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,
@ -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<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");
}

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 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
{

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>
<PackageReference Include="Volo.Abp.Identity.Domain" />
<ProjectReference Include="..\LINGYUN.Abp.Identity.Domain\LINGYUN.Abp.Identity.Domain.csproj" />
</ItemGroup>
</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.Modularity;
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.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<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()
@ -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
{

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 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;
}
}

Loading…
Cancel
Save