diff --git a/apps/vue/src/api/account/claims.ts b/apps/vue/src/api/account/claims.ts new file mode 100644 index 000000000..597054b44 --- /dev/null +++ b/apps/vue/src/api/account/claims.ts @@ -0,0 +1,13 @@ +import { defAbpHttp } from '/@/utils/http/abp'; +import { ChangeAvatar } from './model/claimsModel'; + +enum Api { + ChangeAvatar = '/api/account/my-claim/change-avatar', +} + +export const changeAvatar = (input: ChangeAvatar) => { + return defAbpHttp.post({ + url: Api.ChangeAvatar, + data: input, + }); +}; \ No newline at end of file diff --git a/apps/vue/src/api/account/model/claimsModel.ts b/apps/vue/src/api/account/model/claimsModel.ts new file mode 100644 index 000000000..4e25f17e2 --- /dev/null +++ b/apps/vue/src/api/account/model/claimsModel.ts @@ -0,0 +1,3 @@ +export interface ChangeAvatar { + avatarUrl: string; +} diff --git a/apps/vue/src/api/account/model/profilesModel.ts b/apps/vue/src/api/account/model/profilesModel.ts index 46e74c735..b29236c2e 100644 --- a/apps/vue/src/api/account/model/profilesModel.ts +++ b/apps/vue/src/api/account/model/profilesModel.ts @@ -28,8 +28,3 @@ export interface ChangePhoneNumber { export interface TwoFactorEnabled { enabled: boolean; } - -export interface IdentityUserClaimSet { - claimType: string; - claimValue: string; -} diff --git a/apps/vue/src/api/account/profiles.ts b/apps/vue/src/api/account/profiles.ts index 73233e401..e33976f03 100644 --- a/apps/vue/src/api/account/profiles.ts +++ b/apps/vue/src/api/account/profiles.ts @@ -5,18 +5,16 @@ import { ChangePassword, ChangePhoneNumber, TwoFactorEnabled, - IdentityUserClaimSet, } from './model/profilesModel'; enum Api { - Get = '/api/identity/my-profile', - Update = '/api/identity/my-profile', - ChangePassword = '/api/identity/my-profile/change-password', - SendChangePhoneNumberCode = '/api/identity/my-profile/send-phone-number-change-code', - ChangePhoneNumber = '/api/identity/my-profile/change-phone-number', - GetTwoFactorEnabled = '/api/identity/my-profile/two-factor', - ChangeTwoFactorEnabled = '/api/identity/my-profile/change-two-factor', - SetClaim = '/api/identity/my-profile/claims', + Get = '/api/account/my-profile', + Update = '/api/account/my-profile', + ChangePassword = '/api/account/my-profile/change-password', + SendChangePhoneNumberCode = '/api/account/my-profile/send-phone-number-change-code', + ChangePhoneNumber = '/api/account/my-profile/change-phone-number', + GetTwoFactorEnabled = '/api/account/my-profile/two-factor', + ChangeTwoFactorEnabled = '/api/account/my-profile/change-two-factor', } export const get = () => { @@ -39,13 +37,6 @@ export const changePassword = (input: ChangePassword) => { }); }; -export const setClaim = (input: IdentityUserClaimSet) => { - return defAbpHttp.put({ - url: Api.SetClaim, - data: input, - }); -}; - export const sendChangePhoneNumberCode = (phoneNumber: string) => { return defAbpHttp.put({ url: Api.SendChangePhoneNumberCode, diff --git a/apps/vue/src/api/oss-management/oss.ts b/apps/vue/src/api/oss-management/oss.ts index 1e22d1321..ad6c7d643 100644 --- a/apps/vue/src/api/oss-management/oss.ts +++ b/apps/vue/src/api/oss-management/oss.ts @@ -48,6 +48,8 @@ export const downloadBlob = (bucket: string, path: string, object: string) => { accept: 'application/json', }, responseType: 'blob', + }, { + apiUrl: '/api' }); }; diff --git a/apps/vue/src/api/oss-management/private.ts b/apps/vue/src/api/oss-management/private.ts index 0274280c6..b6713eced 100644 --- a/apps/vue/src/api/oss-management/private.ts +++ b/apps/vue/src/api/oss-management/private.ts @@ -5,7 +5,7 @@ import { AxiosResponse } from 'axios'; import { ListResultDto } from '../model/baseModel'; enum Api { - Upload = '/api/api/files/private/{path}/{name}', + Upload = '/api/api/files/private', Get = '/api/api/files/private/p/{path}/{name}', GetList = '/api/files/private/search', Share = '/api/files/private/share', @@ -21,9 +21,10 @@ export const upload = (file: Blob, path: string, name: string) => { defHttp .uploadFile( { - url: format(Api.Upload, { path: path, name: name }), + url: Api.Upload, }, { + data: { path: path, object: name }, file: file, }, ) diff --git a/apps/vue/src/enums/httpEnum.ts b/apps/vue/src/enums/httpEnum.ts index 4944af5c2..493916d6c 100644 --- a/apps/vue/src/enums/httpEnum.ts +++ b/apps/vue/src/enums/httpEnum.ts @@ -2,10 +2,9 @@ * @description: Request result set */ export enum ResultEnum { + CODE = '0', SUCCESS = 0, - ERROR = 1, - TIMEOUT = 401, - TYPE = 'success', + MESSAGE = 'OK', } /** diff --git a/apps/vue/src/layouts/default/header/components/notify/useMessages.ts b/apps/vue/src/layouts/default/header/components/notify/useMessages.ts index e3b0129f5..8b679e580 100644 --- a/apps/vue/src/layouts/default/header/components/notify/useMessages.ts +++ b/apps/vue/src/layouts/default/header/components/notify/useMessages.ts @@ -29,7 +29,7 @@ export function useMessages() { const { createConfirm, createMessage } = useMessage(); const signalR = useSignalR({ autoStart: false, - serverUrl: '/signalr-hubs/messages', + serverUrl: '/signalr-hubs/signalr-hubs/messages', }); onMounted(() => { diff --git a/apps/vue/src/layouts/default/header/components/notify/useNotifications.ts b/apps/vue/src/layouts/default/header/components/notify/useNotifications.ts index c743cd250..f79a5adb0 100644 --- a/apps/vue/src/layouts/default/header/components/notify/useNotifications.ts +++ b/apps/vue/src/layouts/default/header/components/notify/useNotifications.ts @@ -26,7 +26,7 @@ export function useNotifications() { list: [], }); const signalR = useSignalR({ - serverUrl: '/signalr-hubs/notifications', + serverUrl: '/signalr-hubs/signalr-hubs/notifications', }); onMounted(() => { diff --git a/apps/vue/src/utils/http/axios/index.ts b/apps/vue/src/utils/http/axios/index.ts index 34d873b0f..455453406 100644 --- a/apps/vue/src/utils/http/axios/index.ts +++ b/apps/vue/src/utils/http/axios/index.ts @@ -7,9 +7,11 @@ import type { AxiosTransform, CreateAxiosOptions } from './axiosTransform'; import { VAxios } from './Axios'; import { checkResponse } from './checkStatus'; import { useGlobSetting } from '/@/hooks/setting'; -import { RequestEnum, ContentTypeEnum } from '/@/enums/httpEnum'; +import { useMessage } from '/@/hooks/web/useMessage'; +import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum'; import { isString } from '/@/utils/is'; import { getToken } from '/@/utils/auth'; +import { useI18n } from '/@/hooks/web/useI18n'; import { setObjToUrlParams, deepMerge } from '/@/utils'; import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog'; import { joinTimestamp, formatRequestDate } from './helper'; @@ -18,6 +20,7 @@ import { Persistent } from '../../cache/persistent'; const globSetting = useGlobSetting(); const urlPrefix = globSetting.urlPrefix; +const { createMessage, createErrorModal } = useMessage(); /** * @description: 数据处理,方便区分多种处理方式 @@ -27,14 +30,39 @@ const transform: AxiosTransform = { * @description: 处理请求数据。如果数据不是预期格式,可直接抛出错误 */ transformRequestHook: (res: AxiosResponse, options: RequestOptions) => { + const { t } = useI18n(); const { isReturnNativeResponse } = options; // 是否返回原生响应头 比如:需要获取响应头时使用该属性 if (isReturnNativeResponse) { return res; } + + const { data } = res; + if (!data) { + // return '[HTTP] Request has no return value'; + throw new Error(t('sys.api.apiRequestFailed')); + } + + // 对包装结果处理 + if (res.headers['_abpwrapresult'] === 'true') { + const { code, result, message, details } = data; + const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.CODE; + if (hasSuccess) { + return result; + } + + const title = details ? message : t('sys.api.errorTip'); + const content = details ? details : message; + if (options.errorMessageMode === 'modal') { + createErrorModal({ title: title, content: content }); + } else if (options.errorMessageMode === 'message') { + createMessage.error(content); + } + + throw new Error(content || t('sys.api.apiRequestFailed')); + } + return res.data; - // 不进行任何处理,直接返回 - // 用于页面代码可能需要直接获取code,data,message这些信息时开启 }, // 请求之前处理config diff --git a/apps/vue/src/views/account/setting/BaseSetting.vue b/apps/vue/src/views/account/setting/BaseSetting.vue index fd1db6e97..cbac82555 100644 --- a/apps/vue/src/views/account/setting/BaseSetting.vue +++ b/apps/vue/src/views/account/setting/BaseSetting.vue @@ -37,7 +37,8 @@ import headerImg from '/@/assets/icons/64x64/color-user.png'; import { useUserStore } from '/@/store/modules/user'; import { upload } from '/@/api/oss-management/private'; - import { get as getProfile, update as updateProfile, setClaim } from '/@/api/account/profiles'; + import { changeAvatar } from '/@/api/account/claims'; + import { get as getProfile, update as updateProfile } from '/@/api/account/profiles'; import { UpdateMyProfile } from '/@/api/account/model/profilesModel'; import { useLocalization } from '/@/hooks/abp/useLocalization'; import { useProfile } from './useProfile'; @@ -83,14 +84,9 @@ upload(params.file, 'avatar', params.filename) .then((res) => { const path = encodeURIComponent(res.data.path.substring(0, res.data.path.length - 1)); - setClaim({ - claimType: 'avatarUrl', - claimValue: `${path}/${res.data.name}`, - }) - .then(() => { - resolve(res as unknown as void); - }) - .catch((err) => reject(err)); + changeAvatar({ avatarUrl: `${path}/${res.data.name}` }).then(() => { + resolve(res as unknown as void); + }).catch((err) => reject(err)); }) .catch((err) => reject(err)); }); diff --git a/apps/vue/src/views/oss-management/objects/components/OssPreviewModal.vue b/apps/vue/src/views/oss-management/objects/components/OssPreviewModal.vue index 1315fd024..53c845c24 100644 --- a/apps/vue/src/views/oss-management/objects/components/OssPreviewModal.vue +++ b/apps/vue/src/views/oss-management/objects/components/OssPreviewModal.vue @@ -15,7 +15,8 @@ import { ImagePreview } from '/@/components/Preview'; import { BasicModal, useModalInner } from '/@/components/Modal'; import { OssObject } from '/@/api/oss-management/model/ossModel'; - import { downloadBlob } from '/@/api/oss-management/oss'; + import { generateOssUrl } from '/@/api/oss-management/oss'; + import { useUserStoreWithOut } from '/@/store/modules/user'; export default defineComponent({ name: 'OssPreviewModal', @@ -29,21 +30,14 @@ bucket.value = data.bucket; objects.value = data.objects; }); + const userStore = useUserStoreWithOut(); watch( () => unref(objects), - async (objs) => { - previewImages.value = []; - const images: any[] = []; - for (let i = 0; i < objs.length; i++) { - const blob = await downloadBlob(unref(bucket), objs[i].path, objs[i].name); - images.push({ - src: URL.createObjectURL(blob), - width: '100%', - height: '100%', - }); - } - previewImages.value = images; + (objs) => { + previewImages.value = objs.map(x => { + return generateOssUrl(unref(bucket), x.path, x.name) + "?access_token=" + userStore.getToken; + }); }, ); diff --git a/apps/vue/types/axios.d.ts b/apps/vue/types/axios.d.ts index e60187f9f..865aa1a52 100644 --- a/apps/vue/types/axios.d.ts +++ b/apps/vue/types/axios.d.ts @@ -26,9 +26,9 @@ export interface RequestOptions { } export interface Result { - code: number; - type: 'success' | 'error' | 'warning'; + code: number | string; message: string; + details?: string; result: T; } diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/ChangeAvatarInput.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/ChangeAvatarInput.cs new file mode 100644 index 000000000..872bfe081 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/Dto/ChangeAvatarInput.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Identity; +using Volo.Abp.Validation; + +namespace LINGYUN.Abp.Account +{ + public class ChangeAvatarInput + { + [DynamicMaxLength(typeof(IdentityUserClaimConsts), nameof(IdentityUserClaimConsts.MaxClaimValueLength))] + public string AvatarUrl { get; set; } + } +} 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 new file mode 100644 index 000000000..c1fa258d2 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application.Contracts/LINGYUN/Abp/Account/IMyClaimAppService.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.Account +{ + public interface IMyClaimAppService : IApplicationService + { + 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 0590ec820..099033936 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 @@ -5,12 +5,6 @@ namespace LINGYUN.Abp.Account { public interface IMyProfileAppService : IApplicationService { - /// - /// 设置声明 - /// - /// - /// - Task SetClaimAsync(ChangeUserClaimInput input); /// /// 获取二次认证状态 /// diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs index ff4fa9f5f..fa789f53c 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs @@ -12,8 +12,6 @@ using System.ComponentModel.DataAnnotations; using System.Text; using System.Threading.Tasks; using Volo.Abp; -using Volo.Abp.Account.Localization; -using Volo.Abp.Application.Services; using Volo.Abp.Caching; using Volo.Abp.Identity; using Volo.Abp.Settings; @@ -22,40 +20,29 @@ using IIdentityUserRepository = LINGYUN.Abp.Identity.IIdentityUserRepository; namespace LINGYUN.Abp.Account { - public class AccountAppService : ApplicationService, IAccountAppService + public class AccountAppService : AccountApplicationServiceBase, IAccountAppService { protected ITotpService TotpService { get; } - protected IdentityUserStore UserStore { get; } - protected IdentityUserManager UserManager { get; } protected IIdentityUserRepository UserRepository { get; } protected IUserSecurityCodeSender SecurityCodeSender { get; } protected IWeChatOpenIdFinder WeChatOpenIdFinder { get; } - protected IOptions IdentityOptions { get; } protected AbpWeChatMiniProgramOptionsFactory MiniProgramOptionsFactory { get; } protected IDistributedCache SecurityTokenCache { get; } public AccountAppService( ITotpService totpService, - IdentityUserStore userStore, - IdentityUserManager userManager, IWeChatOpenIdFinder weChatOpenIdFinder, IIdentityUserRepository userRepository, IUserSecurityCodeSender securityCodeSender, IDistributedCache securityTokenCache, - AbpWeChatMiniProgramOptionsFactory miniProgramOptionsFactory, - IOptions identityOptions) + AbpWeChatMiniProgramOptionsFactory miniProgramOptionsFactory) { TotpService = totpService; - UserStore = userStore; - UserManager = userManager; UserRepository = userRepository; WeChatOpenIdFinder = weChatOpenIdFinder; SecurityCodeSender = securityCodeSender; SecurityTokenCache = securityTokenCache; MiniProgramOptionsFactory = miniProgramOptionsFactory; - IdentityOptions = identityOptions; - - LocalizationResource = typeof(AccountResource); } public virtual async Task RegisterAsync(WeChatRegisterDto input) diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountApplicationServiceBase.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountApplicationServiceBase.cs new file mode 100644 index 000000000..55e3d575a --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountApplicationServiceBase.cs @@ -0,0 +1,29 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using System.Threading.Tasks; +using Volo.Abp.Account.Localization; +using Volo.Abp.Application.Services; +using Volo.Abp.Identity; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.Account +{ + public abstract class AccountApplicationServiceBase : ApplicationService + { + protected IOptions IdentityOptions => LazyServiceProvider.LazyGetRequiredService>(); + protected IdentityUserStore UserStore => LazyServiceProvider.LazyGetRequiredService(); + protected IdentityUserManager UserManager => LazyServiceProvider.LazyGetRequiredService(); + + protected AccountApplicationServiceBase() + { + LocalizationResource = typeof(AccountResource); + } + + protected virtual async Task GetCurrentUserAsync() + { + await IdentityOptions.SetAsync(); + + return await UserManager.GetByIdAsync(CurrentUser.GetId()); + } + } +} 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 new file mode 100644 index 000000000..1e9f06897 --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/MyClaimAppService.cs @@ -0,0 +1,29 @@ +using LINGYUN.Abp.Identity; +using Microsoft.AspNetCore.Identity; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Account +{ + public class MyClaimAppService : AccountApplicationServiceBase, IMyClaimAppService + { + public MyClaimAppService() + { + + } + + public virtual async Task ChangeAvatarAsync(ChangeAvatarInput input) + { + var user = await GetCurrentUserAsync(); + + user.Claims.RemoveAll(x => x.ClaimType.Equals(IdentityConsts.ClaimType.Avatar.Name)); + + user.AddClaim(GuidGenerator, new Claim(IdentityConsts.ClaimType.Avatar.Name, input.AvatarUrl)); + + (await UserManager.UpdateAsync(user)).CheckErrors(); + + await CurrentUnitOfWork.SaveChangesAsync(); + } + } +} 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 65fe4d7a6..b4494b0ba 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 @@ -2,72 +2,37 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Caching.Distributed; -using Microsoft.Extensions.Options; using System; -using System.Security.Claims; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Account.Localization; -using Volo.Abp.Application.Services; using Volo.Abp.Caching; -using Volo.Abp.Identity; using Volo.Abp.Settings; -using Volo.Abp.Users; namespace LINGYUN.Abp.Account { [Authorize] - public class MyProfileAppService : ApplicationService, IMyProfileAppService + public class MyProfileAppService : AccountApplicationServiceBase, IMyProfileAppService { protected IDistributedCache SecurityTokenCache { get; } protected IUserSecurityCodeSender SecurityCodeSender { get; } - protected IdentityUserManager UserManager { get; } protected Identity.IIdentityUserRepository UserRepository { get; } - protected IOptions IdentityOptions { get; } public MyProfileAppService( - IdentityUserManager userManager, Identity.IIdentityUserRepository userRepository, IUserSecurityCodeSender securityCodeSender, - IOptions identityOptions, IDistributedCache securityTokenCache) { - UserManager = userManager; UserRepository = userRepository; - IdentityOptions = identityOptions; SecurityCodeSender = securityCodeSender; SecurityTokenCache = securityTokenCache; LocalizationResource = typeof(AccountResource); } - public virtual async Task SetClaimAsync(ChangeUserClaimInput input) - { - await IdentityOptions.SetAsync(); - var user = await UserManager.GetByIdAsync(CurrentUser.GetId()); - - var newClaim = new Claim(input.ClaimType, input.ClaimValue); - var currentClaim = user.FindClaim(newClaim); - if (currentClaim != null) - { - // Replace With Claim Value Empty? - // (await UserManager.ReplaceClaimAsync(user, currentClaim.ToClaim(), newClaim)).CheckErrors(); - user.ReplaceClaim(currentClaim.ToClaim(), newClaim); - } - else - { - // (await UserManager.AddClaimAsync(user, newClaim)).CheckErrors(); - user.AddClaim(GuidGenerator, newClaim); - } - (await UserManager.UpdateAsync(user)).CheckErrors(); - - await CurrentUnitOfWork.SaveChangesAsync(); - } - public virtual async Task GetTwoFactorEnabledAsync() { - await IdentityOptions.SetAsync(); - var user = await UserManager.GetByIdAsync(CurrentUser.GetId()); + var user = await GetCurrentUserAsync(); return new TwoFactorEnabledDto { @@ -83,8 +48,7 @@ namespace LINGYUN.Abp.Account // throw new BusinessException(Volo.Abp.Identity.IdentityErrorCodes.CanNotChangeTwoFactor); //} // TODO: Abp官方移除了双因素的设置,不排除以后会增加,如果在用户接口中启用了双因素认证,可能造成登录失败! - await IdentityOptions.SetAsync(); - var user = await UserManager.GetByIdAsync(CurrentUser.GetId()); + var user = await GetCurrentUserAsync(); (await UserManager.SetTwoFactorEnabledWithAccountConfirmedAsync(user, input.Enabled)).CheckErrors(); @@ -106,7 +70,8 @@ namespace LINGYUN.Abp.Account { throw new BusinessException(Identity.IdentityErrorCodes.DuplicatePhoneNumber); } - var user = await UserManager.GetByIdAsync(CurrentUser.GetId()); + var user = await GetCurrentUserAsync(); + var template = await SettingProvider.GetOrNullAsync(Identity.Settings.IdentitySettingNames.User.SmsPhoneNumberConfirmed); var token = await UserManager.GenerateChangePhoneNumberTokenAsync(user, input.NewPhoneNumber); // 发送验证码 @@ -128,9 +93,7 @@ namespace LINGYUN.Abp.Account { throw new BusinessException(Identity.IdentityErrorCodes.DuplicatePhoneNumber); } - await IdentityOptions.SetAsync(); - //TODO: 可以查询缓存用 securityTokenCacheItem.SecurityToken 与 user.SecurityStamp 作对比 - var user = await UserManager.GetByIdAsync(CurrentUser.GetId()); + var user = await GetCurrentUserAsync(); // 更换手机号 (await UserManager.ChangePhoneNumberAsync(user, input.NewPhoneNumber, input.Code)).CheckErrors(); diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/MyClaimController.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/MyClaimController.cs new file mode 100644 index 000000000..a568716bc --- /dev/null +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.HttpApi/LINGYUN/Abp/Account/MyClaimController.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Account; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.Account +{ + [RemoteService(Name = AccountRemoteServiceConsts.RemoteServiceName)] + [Area("account")] + [ControllerName("Profile")] + [Route("/api/account/my-claim")] + public class MyClaimController : AbpController, IMyClaimAppService + { + private readonly IMyClaimAppService _service; + + public MyClaimController( + IMyClaimAppService service) + { + _service = service; + } + + [HttpPost] + [Route("change-avatar")] + public virtual async Task ChangeAvatarAsync(ChangeAvatarInput input) + { + await _service.ChangeAvatarAsync(input); + } + } +} 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 a7da2d9c3..20024bd43 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 @@ -1,12 +1,12 @@ using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using Volo.Abp; +using Volo.Abp.Account; using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.Identity; namespace LINGYUN.Abp.Account { - [RemoteService(Name = IdentityRemoteServiceConsts.RemoteServiceName)] + [RemoteService(Name = AccountRemoteServiceConsts.RemoteServiceName)] [Area("account")] [ControllerName("Profile")] [Route("/api/account/my-profile")] @@ -20,13 +20,6 @@ namespace LINGYUN.Abp.Account MyProfileAppService = myProfileAppService; } - [HttpPut] - [Route("claims")] - public virtual async Task SetClaimAsync(ChangeUserClaimInput input) - { - await MyProfileAppService.SetClaimAsync(input); - } - [HttpGet] [Route("two-factor")] public virtual async Task GetTwoFactorEnabledAsync() diff --git a/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/IdentityConsts.cs b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/IdentityConsts.cs new file mode 100644 index 000000000..e0e3fd083 --- /dev/null +++ b/aspnet-core/modules/identity/LINGYUN.Abp.Identity.Domain.Shared/LINGYUN/Abp/Identity/IdentityConsts.cs @@ -0,0 +1,15 @@ +namespace LINGYUN.Abp.Identity +{ + public static class IdentityConsts + { + public static class ClaimType + { + public static class Avatar + { + public static string Name { get; set; } = "avatarUrl"; + public static string DisplayName { get; set; } = "Your avatar url"; + public static string Description { get; set; } = "Your avatar url"; + } + } + } +} diff --git a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs index e05b9ebfa..5211cdf38 100644 --- a/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs +++ b/aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.Configure.cs @@ -15,6 +15,7 @@ using System; using System.IO; using System.Text.Encodings.Web; using System.Text.Unicode; +using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Auditing; using Volo.Abp.BlobStoring; @@ -258,6 +259,20 @@ public partial class PlatformManagementHttpApiHostModule options.Authority = configuration["AuthServer:Authority"]; options.RequireHttpsMetadata = false; options.Audience = configuration["AuthServer:ApiName"]; + options.Events = new JwtBearerEvents + { + OnMessageReceived = context => + { + var accessToken = context.Request.Query["access_token"]; + var path = context.HttpContext.Request.Path; + if (!string.IsNullOrEmpty(accessToken) && + (path.StartsWithSegments("/api/files"))) + { + context.Token = accessToken; + } + return Task.CompletedTask; + } + }; }); if (!isDevelopment) diff --git a/aspnet-core/services/LY.MicroService.identityServer/IdentityResources/CustomIdentityResources.cs b/aspnet-core/services/LY.MicroService.identityServer/IdentityResources/CustomIdentityResources.cs index ed7ca1eb5..4301213a7 100644 --- a/aspnet-core/services/LY.MicroService.identityServer/IdentityResources/CustomIdentityResources.cs +++ b/aspnet-core/services/LY.MicroService.identityServer/IdentityResources/CustomIdentityResources.cs @@ -1,4 +1,5 @@ using IdentityServer4.Models; +using LINGYUN.Abp.Identity; namespace LY.MicroService.IdentityServer.IdentityResources; @@ -6,13 +7,13 @@ public class CustomIdentityResources { public class AvatarUrl : IdentityResource { - public static string ClaimType { get; set; } = "avatarUrl"; public AvatarUrl() { - Name = ClaimType; - DisplayName = "Your avatar url"; + Name = IdentityConsts.ClaimType.Avatar.Name; + DisplayName = IdentityConsts.ClaimType.Avatar.DisplayName; + Description = IdentityConsts.ClaimType.Avatar.Description; Emphasize = true; - UserClaims = new string[] { ClaimType }; + UserClaims = new string[] { IdentityConsts.ClaimType.Avatar.Name }; } } } diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/LINGYUN.MicroService.Internal.ApiGateway.sln b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/LINGYUN.MicroService.Internal.ApiGateway.sln new file mode 100644 index 000000000..39743f748 --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/LINGYUN.MicroService.Internal.ApiGateway.sln @@ -0,0 +1,21 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.MicroService.Internal.ApiGateway", "src\LINGYUN.MicroService.Internal.ApiGateway\LINGYUN.MicroService.Internal.ApiGateway.csproj", "{00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E8067AED-2B6E-4134-AAF8-9101457D709A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {00A2F7A3-BEC3-48F4-A91C-5A336C32A5D2} = {E8067AED-2B6E-4134-AAF8-9101457D709A} + EndGlobalSection +EndGlobal diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/InternalApiGatewayModule.cs b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/InternalApiGatewayModule.cs index 744e2946e..7fca53e66 100644 --- a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/InternalApiGatewayModule.cs +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/InternalApiGatewayModule.cs @@ -53,7 +53,6 @@ namespace LINGYUN.MicroService.Internal.ApiGateway public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); - var sss = app.ApplicationServices.GetRequiredService>(); app.UseForwardedHeaders(); app.UseAuditing(); app.UseStaticFiles(); diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.Development.json b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.Development.json index f1ee9fe89..776dbbe59 100644 --- a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.Development.json +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.Development.json @@ -940,6 +940,42 @@ "UseTracing": true } }, + { + "DownstreamPathTemplate": "/api/my-subscribes", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "127.0.0.1", + "Port": 30020 + } + ], + "UpstreamPathTemplate": "/api/my-subscribes", + "UpstreamHttpMethod": [ + "GET", + "POST", + "PUT", + "DELETE" + ], + "LoadBalancerOptions": { + "Type": "RoundRobin" + }, + "RateLimitOptions": { + "ClientWhitelist": [], + "EnableRateLimiting": true, + "Period": "1s", + "PeriodTimespan": 1, + "Limit": 5 + }, + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 10, + "DurationOfBreak": 1000, + "TimeoutValue": 10000 + }, + "HttpHandlerOptions": { + "UseTracing": true + }, + "Priority": 99 + }, { "DownstreamPathTemplate": "/api/my-subscribes/{everything}", "DownstreamScheme": "http", @@ -1299,6 +1335,41 @@ "UseTracing": true } }, + { + "DownstreamPathTemplate": "/api/files/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "127.0.0.1", + "Port": 30025 + } + ], + "UpstreamPathTemplate": "/api/api/files/{everything}", + "UpstreamHttpMethod": [ + "GET", + "POST", + "PUT", + "DELETE" + ], + "LoadBalancerOptions": { + "Type": "RoundRobin" + }, + "RateLimitOptions": { + "ClientWhitelist": [], + "EnableRateLimiting": true, + "Period": "1s", + "PeriodTimespan": 1, + "Limit": 5 + }, + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 10, + "DurationOfBreak": 1000, + "TimeoutValue": 10000 + }, + "HttpHandlerOptions": { + "UseTracing": true + } + }, { "DownstreamPathTemplate": "/api/setting-management/oss-management/by-current-tenant", "DownstreamScheme": "http", @@ -1397,6 +1468,56 @@ "UseTracing": true } }, + { + "DownstreamPathTemplate": "/signalr-hubs/messages", + "DownstreamScheme": "ws", + "DownstreamHostAndPorts": [ + { + "Host": "127.0.0.1", + "Port": 30020 + } + ], + "UpstreamPathTemplate": "/signalr-hubs/messages", + "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ], + "LoadBalancerOptions": { + "Type": "RoundRobin" + }, + "RateLimitOptions": {}, + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 10, + "DurationOfBreak": 1000, + "TimeoutValue": 10000 + }, + "HttpHandlerOptions": {}, + "DangerousAcceptAnyServerCertificateValidator": true, + "RouteIsCaseSensitive": false, + "Priority": 99 + }, + { + "DownstreamPathTemplate": "/signalr-hubs/notifications", + "DownstreamScheme": "ws", + "DownstreamHostAndPorts": [ + { + "Host": "127.0.0.1", + "Port": 30020 + } + ], + "UpstreamPathTemplate": "/signalr-hubs/notifications", + "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ], + "LoadBalancerOptions": { + "Type": "RoundRobin" + }, + "RateLimitOptions": {}, + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 10, + "DurationOfBreak": 1000, + "TimeoutValue": 10000 + }, + "HttpHandlerOptions": {}, + "DangerousAcceptAnyServerCertificateValidator": true, + "RouteIsCaseSensitive": false, + "Priority": 99 + }, { "DownstreamPathTemplate": "/signalr-hubs/{everything}", "DownstreamScheme": "ws", diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.messages.json b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.messages.json index bcbb10688..eb9fffd10 100644 --- a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.messages.json +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.messages.json @@ -114,6 +114,42 @@ "UseTracing": true } }, + { + "DownstreamPathTemplate": "/api/my-subscribes", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "127.0.0.1", + "Port": 30020 + } + ], + "UpstreamPathTemplate": "/api/my-subscribes", + "UpstreamHttpMethod": [ + "GET", + "POST", + "PUT", + "DELETE" + ], + "LoadBalancerOptions": { + "Type": "RoundRobin" + }, + "RateLimitOptions": { + "ClientWhitelist": [], + "EnableRateLimiting": true, + "Period": "1s", + "PeriodTimespan": 1, + "Limit": 5 + }, + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 10, + "DurationOfBreak": 1000, + "TimeoutValue": 10000 + }, + "HttpHandlerOptions": { + "UseTracing": true + }, + "Priority": 99 + }, // �û����� { "DownstreamPathTemplate": "/api/my-subscribes/{everything}", @@ -309,6 +345,56 @@ } }, // ������ + { + "DownstreamPathTemplate": "/signalr-hubs/messages", + "DownstreamScheme": "ws", + "DownstreamHostAndPorts": [ + { + "Host": "127.0.0.1", + "Port": 30020 + } + ], + "UpstreamPathTemplate": "/signalr-hubs/messages", + "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ], + "LoadBalancerOptions": { + "Type": "RoundRobin" + }, + "RateLimitOptions": {}, + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 10, + "DurationOfBreak": 1000, + "TimeoutValue": 10000 + }, + "HttpHandlerOptions": {}, + "DangerousAcceptAnyServerCertificateValidator": true, + "RouteIsCaseSensitive": false, + "Priority": 99 + }, + { + "DownstreamPathTemplate": "/signalr-hubs/notifications", + "DownstreamScheme": "ws", + "DownstreamHostAndPorts": [ + { + "Host": "127.0.0.1", + "Port": 30020 + } + ], + "UpstreamPathTemplate": "/signalr-hubs/notifications", + "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ], + "LoadBalancerOptions": { + "Type": "RoundRobin" + }, + "RateLimitOptions": {}, + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 10, + "DurationOfBreak": 1000, + "TimeoutValue": 10000 + }, + "HttpHandlerOptions": {}, + "DangerousAcceptAnyServerCertificateValidator": true, + "RouteIsCaseSensitive": false, + "Priority": 99 + }, { "DownstreamPathTemplate": "/signalr-hubs/{everything}", "DownstreamScheme": "ws", diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.platform.json b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.platform.json index b375c938a..a7473ea42 100644 --- a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.platform.json +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.Internal.ApiGateway/ocelot.platform.json @@ -1,6 +1,6 @@ { "Routes": [ - // ܶ˵ + // ��ܶ˵� { "DownstreamPathTemplate": "/api/abp/application-configuration", "DownstreamScheme": "http", @@ -26,7 +26,7 @@ }, "Key": "platform-configuration" }, - // ̬ܶAPI˵ + // ��ܶ�̬API�˵� { "DownstreamPathTemplate": "/api/abp/api-definition", "DownstreamScheme": "http", @@ -52,7 +52,7 @@ }, "Key": "platform-api-definition" }, - // 洢 + // ����洢 { "DownstreamPathTemplate": "/api/oss-management/{everything}", "DownstreamScheme": "http", @@ -83,7 +83,7 @@ "UseTracing": true } }, - // ƽ̨ + // ƽ̨���� { "DownstreamPathTemplate": "/api/platform/{everything}", "DownstreamScheme": "http", @@ -114,7 +114,7 @@ "UseTracing": true } }, - // ļ + // �ļ����� { "DownstreamPathTemplate": "/api/files/{everything}", "DownstreamScheme": "http", @@ -145,7 +145,42 @@ "UseTracing": true } }, - // 洢⻧ + { + "DownstreamPathTemplate": "/api/files/{everything}", + "DownstreamScheme": "http", + "DownstreamHostAndPorts": [ + { + "Host": "127.0.0.1", + "Port": 30025 + } + ], + "UpstreamPathTemplate": "/api/api/files/{everything}", + "UpstreamHttpMethod": [ + "GET", + "POST", + "PUT", + "DELETE" + ], + "LoadBalancerOptions": { + "Type": "RoundRobin" + }, + "RateLimitOptions": { + "ClientWhitelist": [], + "EnableRateLimiting": true, + "Period": "1s", + "PeriodTimespan": 1, + "Limit": 5 + }, + "QoSOptions": { + "ExceptionsAllowedBeforeBreaking": 10, + "DurationOfBreak": 1000, + "TimeoutValue": 10000 + }, + "HttpHandlerOptions": { + "UseTracing": true + } + }, + // ����洢�⻧���� { "DownstreamPathTemplate": "/api/setting-management/oss-management/by-current-tenant", "DownstreamScheme": "http", @@ -177,7 +212,7 @@ }, "Key": "oss-management-setting-current-tenant" }, - // 洢ȫ + // ����洢ȫ������ { "DownstreamPathTemplate": "/api/setting-management/oss-management/by-global", "DownstreamScheme": "http", @@ -209,7 +244,7 @@ }, "Key": "oss-management-setting-global" }, - // API ĵ + // API �ĵ� { "DownstreamPathTemplate": "/swagger/v1/swagger.json", "DownstreamScheme": "http",