From 6178c9d4e678b783170a71e271de88d1167b5566 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Thu, 17 Jul 2025 06:42:00 +0330 Subject: [PATCH] last ... --- Constants/XApiAccountEndpoint.cs | 130 +++++++++++++------------ Constants/XParam.cs | 3 + Interfaces/IXIdentityProvider.cs | 144 +++++++++++++++------------- Models/XBaseRestResponse.cs | 10 ++ Partial/XIdentityProvider+Open.cs | 144 ++++++++++++++++++++++++++++ Providers/XIdentityProvider.cs | 151 +++++++++++++++++++++++++++++- 6 files changed, 455 insertions(+), 127 deletions(-) create mode 100644 Models/XBaseRestResponse.cs create mode 100644 Partial/XIdentityProvider+Open.cs diff --git a/Constants/XApiAccountEndpoint.cs b/Constants/XApiAccountEndpoint.cs index b16fb0e..3879764 100644 --- a/Constants/XApiAccountEndpoint.cs +++ b/Constants/XApiAccountEndpoint.cs @@ -1,197 +1,205 @@ using xExceptions.Attributes; -namespace xIdentityService.Constants { - public enum XApiAccountEndpoint { +namespace xIdentityService.Constants +{ + public enum XApiAccountEndpoint + { // #region Authentication ... - [StringValue ("Account/DiscoveryDocument")] + [StringValue("Account/DiscoveryDocument")] DiscoveryDocument, - [StringValue ("Account/RequestScopeAccessToken")] + [StringValue("Account/RequestScopeAccessToken")] RequestScopeAccessToken, - [StringValue ("Account/Authenticate")] + [StringValue("Account/Authenticate")] Authenticate, - [StringValue ("Account/Login")] + [StringValue("Account/Login")] Login, - [StringValue ("Account/RefreshTokens")] + [StringValue("Account/RefreshTokens")] RefreshTokens, - [StringValue ("Account/ChangePassword")] + [StringValue("Account/ChangePassword")] ChangePassword, - [StringValue ("Account/ResetPassword")] + [StringValue("Account/ResetPassword")] ResetPassword, #endregion // #region Proile ... - [StringValue ("Account/Profile/{ids}/GetNames")] + [StringValue("Account/Profile/{ids}/GetNames")] GetNames, - [StringValue ("Account/Profile/GetNameIds")] + [StringValue("Account/Profile/GetNameIds")] GetNameIds, - [StringValue ("Account/Profile/{userSelectByParam}")] + [StringValue("Account/Profile/{userSelectByParam}")] GetProfile, - [StringValue ("Account/Profile/Query")] + [StringValue("Account/Profile/Query")] QueryProfiles, - [StringValue ("Account/Profile/Avatars/Query/{userSelectByParam}")] + [StringValue("Account/Profile/Avatars/Query/{userSelectByParam}")] QueryAvatars, - [StringValue ("Account/Profile/Update/{userSelectByParam}")] + [StringValue("Account/Profile/Update/{userSelectByParam}")] UpdateProfile, - [StringValue ("Account/Profile/{userSelectByParam}")] + [StringValue("Account/Profile/{userSelectByParam}")] FullUpdateProfile, - [StringValue ("Account/Profile/Avatar")] + [StringValue("Account/Profile/Avatar")] AddAvatar, - [StringValue ("Account/Profile/Avatars")] + [StringValue("Account/Profile/Avatars")] AddAvatars, - [StringValue ("Account/Profile/Avatars/{ids}")] + [StringValue("Account/Profile/Avatars/{ids}")] RemoveAvatars, - [StringValue ("Account/Profile/Avatars/{id}/Set")] + [StringValue("Account/Profile/Avatars/{id}/Set")] SetAvatar, #endregion // #region Registration ... - [StringValue ("Account/CanRegisterUserName/{userName}")] + [StringValue("Account/CanRegisterUserName/{userName}")] CanRegisterUserName, - [StringValue ("Account/CanRegisterMobileNumber/{mobileNumber}")] + [StringValue("Account/CanRegisterMobileNumber/{mobileNumber}")] CanRegisterMobileNumber, - [StringValue ("Account/CanRegisterEmail/{email}")] + [StringValue("Account/CanRegisterEmail/{email}")] CanRegisterEmail, - [StringValue ("Account/IsConfirmedEmail")] + [StringValue("Account/IsConfirmedEmail")] IsConfirmedEmail, - [StringValue ("Account/IsConfirmedMobile")] + [StringValue("Account/IsConfirmedMobile")] IsConfirmedMobile, - [StringValue ("Account/ConfirmRegistration")] + [StringValue("Account/ConfirmRegistration")] ConfirmRegistration, - [StringValue ("Account/ConfirmMobileNumber")] + [StringValue("Account/ConfirmMobileNumber")] ConfirmMobileNumber, - [StringValue ("Account/ConfirmEmailAddress")] + [StringValue("Account/ConfirmEmailAddress")] ConfirmEmailAddress, - [StringValue ("Account/RequestConfirmMobile")] + [StringValue("Account/RequestConfirmMobile")] RequestConfirmMobile, - [StringValue ("Account/RequestConfirmEmail")] + [StringValue("Account/RequestConfirmEmail")] RequestConfirmEmail, - [StringValue ("Account/RequestResetPassword")] + [StringValue("Account/RequestResetPassword")] RequestResetPassword, - [StringValue ("Account/RequestConfirmRegistration")] + [StringValue("Account/RequestConfirmRegistration")] RequestConfirmRegistration, - [StringValue ("Account/InviteUser")] + [StringValue("Account/InviteUser")] InviteUser, - [StringValue ("Account/RequestRegistration")] + [StringValue("Account/RequestRegistration")] RequestRegistration, - [StringValue ("Account/AddAccountInfo")] + [StringValue("Account/AddAccountInfo")] AddAccountInfo, - [StringValue ("Account/AttachProfileImage")] + [StringValue("Account/AttachProfileImage")] AttachProfileImage, - [StringValue ("Account/FinishRegistration")] + [StringValue("Account/FinishRegistration")] FinishRegistration, #endregion // #region Friendship ... - [StringValue ("Account/Friendship/{destUser}/Follow")] + [StringValue("Account/Friendship/{destUser}/Follow")] Follow, - [StringValue ("Account/Friendship/{destUser}/Cancel")] + [StringValue("Account/Friendship/{destUser}/Cancel")] Cancel, - [StringValue ("Account/Friendship/{destUser}/UnFollowFollower")] + [StringValue("Account/Friendship/{destUser}/UnFollowFollower")] UnFollowFollower, - [StringValue ("Account/Friendship/{destUser}/UnFollowFollowing")] + [StringValue("Account/Friendship/{destUser}/UnFollowFollowing")] UnFollowFollowing, - [StringValue ("Account/Friendship/{destUser}/Block")] + [StringValue("Account/Friendship/{destUser}/Block")] Block, - [StringValue ("Account/Friendship/{destUser}/UnBlock")] + [StringValue("Account/Friendship/{destUser}/UnBlock")] UnBlock, - [StringValue ("Account/Friendship/{destUser}/AcceptRequest")] + [StringValue("Account/Friendship/{destUser}/AcceptRequest")] AcceptRequest, - [StringValue ("Account/Friendship/{destUser}/RejectRequest")] + [StringValue("Account/Friendship/{destUser}/RejectRequest")] RejectRequest, - [StringValue ("Account/Friendship/{destUser}/IsFollower")] + [StringValue("Account/Friendship/{destUser}/IsFollower")] IsFollower, - [StringValue ("Account/Friendship/{destUser}/FollowerState")] + [StringValue("Account/Friendship/{destUser}/FollowerState")] FollowerState, - [StringValue ("Account/Friendship/{destUser}/Follower")] + [StringValue("Account/Friendship/{destUser}/Follower")] Follower, - [StringValue ("Account/Friendship/Followers")] + [StringValue("Account/Friendship/Followers")] Followers, - [StringValue ("Account/Friendship/AllFollowers")] + [StringValue("Account/Friendship/AllFollowers")] AllFollowers, - [StringValue ("Account/Friendship/{destUser}/IsFollowing")] + [StringValue("Account/Friendship/{destUser}/IsFollowing")] IsFollowing, - [StringValue ("Account/Friendship/{destUser}/FollowingState")] + [StringValue("Account/Friendship/{destUser}/FollowingState")] FollowingState, - [StringValue ("Account/Friendship/{destUser}/Following")] + [StringValue("Account/Friendship/{destUser}/Following")] Following, - [StringValue ("Account/Friendship/Followings")] + [StringValue("Account/Friendship/Followings")] Followings, - [StringValue ("Account/Friendship/AllFollowings")] + [StringValue("Account/Friendship/AllFollowings")] AllFollowings, - [StringValue ("Account/Friendship/FollowingsList")] + [StringValue("Account/Friendship/FollowingsList")] FollowingsList, - [StringValue ("Account/Friendship/FollowersList")] + [StringValue("Account/Friendship/FollowersList")] FollowersList, - [StringValue ("Account/Friendship/{destUser}/FriendshipInfo")] + [StringValue("Account/Friendship/{destUser}/FriendshipInfo")] FriendshipInfo, #endregion // #region Admin ... - [StringValue ("Account/Ban")] + [StringValue("Account/Ban")] Ban, - [StringValue ("Account/UnBan")] + [StringValue("Account/UnBan")] UnBan, - [StringValue ("Account/IsBanned/{userSelectByParam}")] + [StringValue("Account/IsBanned/{userSelectByParam}")] IsBanned, #endregion + + // + #region Open Actions ... + [StringValue("Account/GetUserInfo")] + GetUserInfo, + #endregion } } \ No newline at end of file diff --git a/Constants/XParam.cs b/Constants/XParam.cs index 722d23d..30bf4fc 100644 --- a/Constants/XParam.cs +++ b/Constants/XParam.cs @@ -50,6 +50,9 @@ namespace xIdentityService.Constants { [StringValue ("actionToken")] XActionToken, + [StringValue ("request")] + XRequest, + [StringValue ("scope")] XScope, } diff --git a/Interfaces/IXIdentityProvider.cs b/Interfaces/IXIdentityProvider.cs index 6aa5c1b..e9c160f 100644 --- a/Interfaces/IXIdentityProvider.cs +++ b/Interfaces/IXIdentityProvider.cs @@ -10,15 +10,18 @@ using xIdentityModels.Models; using xIdentityModels.Navigations; using xModels.Dtos; -namespace xIdentityService.Interfaces { - public partial interface IXIdentityProvider { +namespace xIdentityService.Interfaces +{ + public partial interface IXIdentityProvider + { // string BaseUrl { get; } string RevisionSecretKey { get; } + IXSecurityProvider SecurityProvider { get; } // #region Tools ... - string GetUserSelectByParam ( + string GetUserSelectByParam( XActionRequest model, bool forceNotNull = true, ICollection excludes = null @@ -27,7 +30,7 @@ namespace xIdentityService.Interfaces { // #region Tools ... - Task RunRestRequest ( + Task RunRestRequest( RestClient client, RestRequest request, XHttpMethod method, @@ -37,15 +40,15 @@ namespace xIdentityService.Interfaces { // #region Authentication ... - Task RequestDiscoveryDocument (); - Task RequestScopeAccessToken (string scope); - Task Introspection (XTokenResponse model); - Task Login (XLoginRequest model); - Task Logout (XTokenResponse model); - Task Authenticate (XLoginRequest model); - Task RefreshTokens (XTokenResponse model); + Task RequestDiscoveryDocument(); + Task RequestScopeAccessToken(string scope); + Task Introspection(XTokenResponse model); + Task Login(XLoginRequest model); + Task Logout(XTokenResponse model); + Task Authenticate(XLoginRequest model); + Task RefreshTokens(XTokenResponse model); - Task ChangePassword ( + Task ChangePassword( XTokenResponse tokens, XActionRequest model ); @@ -53,67 +56,67 @@ namespace xIdentityService.Interfaces { // #region Profile ... - Task> GetUserNames ( + Task> GetUserNames( XTokenResponse tokens, string userIds ); - Task> GetUserNameIds ( + Task> GetUserNameIds( XTokenResponse tokens, XUserNameIdRequest model ); - Task GetUserProfile ( + Task GetUserProfile( XTokenResponse tokens, string userSelectByParam ); - Task> QueryUsers ( + Task> QueryUsers( XTokenResponse tokens, XQuery query ); - Task> QueryInRoleUsers ( + Task> QueryInRoleUsers( XTokenResponse tokens, string role, XQuery query, bool forceRole = false ); - Task> QueryAvatars ( + Task> QueryAvatars( XTokenResponse tokens, string userSelectByParam, XQuery query ); - Task ProfileUpdateAsync ( + Task ProfileUpdateAsync( XTokenResponse tokens, string userSelectByParam, XProfileUpdateRequest model ); - Task FullProfileUpdateAsync ( + Task FullProfileUpdateAsync( XTokenResponse tokens, string userSelectByParam, XProfileUpdateRequest request ); - Task AddAvatar ( + Task AddAvatar( XTokenResponse tokens, IFormFile file ); - Task AddAvatars ( + Task AddAvatars( XTokenResponse tokens, IFormFileCollection files ); - Task SetAvatar ( + Task SetAvatar( XTokenResponse tokens, int avatarId ); - Task RemoveAvatars ( + Task RemoveAvatars( XTokenResponse tokens, string avatarIds ); @@ -121,142 +124,142 @@ namespace xIdentityService.Interfaces { // #region Registration ... - Task CanRegister (string userSelectByParam); + Task CanRegister(string userSelectByParam); - Task InviteUser ( + Task InviteUser( XTokenResponse tokens, XActionRequest model ); - Task RequestRegistration ( + Task RequestRegistration( XActionRequest model ); - Task AddAccountInfo ( + Task AddAccountInfo( XActionRequest model ); - Task AttachProfileImage ( + Task AttachProfileImage( string actionToken, IFormFile file ); - Task FinishRegistration (XActionRequest model); + Task FinishRegistration(XActionRequest model); - Task IsConfirmedEmail ( + Task IsConfirmedEmail( XTokenResponse tokens, string userSelectByParam ); - Task IsConfirmedMobile ( + Task IsConfirmedMobile( XTokenResponse tokens, string userSelectByParam ); - Task RequestConfirmRegistration (XActionRequest model); + Task RequestConfirmRegistration(XActionRequest model); - Task ConfirmRegistration ( + Task ConfirmRegistration( XActionRequest model ); - Task RequestConfirmMobile (XActionRequest model); + Task RequestConfirmMobile(XActionRequest model); - Task ConfirmMobileNumber (XActionRequest model); + Task ConfirmMobileNumber(XActionRequest model); - Task RequestConfirmEmail (XActionRequest model); + Task RequestConfirmEmail(XActionRequest model); - Task ConfirmEmailAddress (XActionRequest model); + Task ConfirmEmailAddress(XActionRequest model); - Task RequestResetPassword (XActionRequest model); + Task RequestResetPassword(XActionRequest model); - Task ResetPassword (XActionRequest model); + Task ResetPassword(XActionRequest model); #endregion // #region Friendship ... - Task Follow ( + Task Follow( XTokenResponse tokens, string destUser ); - Task Cancel ( + Task Cancel( XTokenResponse tokens, string destUser ); - Task UnFollowFollower ( + Task UnFollowFollower( XTokenResponse tokens, string destUser ); - Task UnFollowFollowing ( + Task UnFollowFollowing( XTokenResponse tokens, string destUser ); - Task Block ( + Task Block( XTokenResponse tokens, string destUser ); - Task UnBlock ( + Task UnBlock( XTokenResponse tokens, string destUser ); - Task AcceptRequest ( + Task AcceptRequest( XTokenResponse tokens, string destUser ); - Task RejectRequest ( + Task RejectRequest( XTokenResponse tokens, string destUser ); - Task IsFollower ( + Task IsFollower( XTokenResponse tokens, string destUser ); - Task GetFollower ( + Task GetFollower( XTokenResponse tokens, string destUser ); - Task GetFollowerState ( + Task GetFollowerState( XTokenResponse tokens, string destUser ); - Task> GetFollowers (XTokenResponse tokens); + Task> GetFollowers(XTokenResponse tokens); - Task> GetAllFollowers (XTokenResponse tokens); + Task> GetAllFollowers(XTokenResponse tokens); - Task IsFollowing ( + Task IsFollowing( XTokenResponse tokens, string destUser ); - Task GetFollowing ( + Task GetFollowing( XTokenResponse tokens, string destUser ); - Task GetFollowingState ( + Task GetFollowingState( XTokenResponse tokens, string destUser ); - Task> GetFollowings (XTokenResponse tokens); + Task> GetFollowings(XTokenResponse tokens); - Task> GetAllFollowings (XTokenResponse tokens); + Task> GetAllFollowings(XTokenResponse tokens); - Task> GetFollowingList (XTokenResponse tokens); + Task> GetFollowingList(XTokenResponse tokens); - Task> GetFollowersList (XTokenResponse tokens); + Task> GetFollowersList(XTokenResponse tokens); - Task GetFriendshipInfo ( + Task GetFriendshipInfo( XTokenResponse tokens, string destUser ); @@ -264,20 +267,33 @@ namespace xIdentityService.Interfaces { // #region Admin ... - Task> Ban ( + Task> Ban( XTokenResponse tokens, XUserNameIdRequest model ); - Task> UnBan ( + Task> UnBan( XTokenResponse tokens, XUserNameIdRequest model ); - Task IsBanned ( + Task IsBanned( XTokenResponse tokens, string userSelectByParam ); #endregion + + // + #region Open Actions ... + Task GetUserInfo( + XDeviceDto device, + string userSelectByParam + ); + Task GetUserInfo(XOpenActionInnerDto dto); + Task GetUserInfo( + string token, + string request + ); + #endregion } } \ No newline at end of file diff --git a/Models/XBaseRestResponse.cs b/Models/XBaseRestResponse.cs new file mode 100644 index 0000000..a5e35e5 --- /dev/null +++ b/Models/XBaseRestResponse.cs @@ -0,0 +1,10 @@ +using RestSharp; + +namespace xIdentityService.Models +{ + public class XBaseRestResponse + { + public T Model { get; set; } + public IRestResponse Response { get; set; } + } +} \ No newline at end of file diff --git a/Partial/XIdentityProvider+Open.cs b/Partial/XIdentityProvider+Open.cs new file mode 100644 index 0000000..e3fdca2 --- /dev/null +++ b/Partial/XIdentityProvider+Open.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using MongoDB.Bson; +using xCommons.Constants; +using xCommons.Extensions; +using xExceptions.Constants; +using xHttpService.Constants; +using xIdentityModels.Dtos; +using xIdentityService.Constants; +using xModels.Dtos; +using xModels.Extensions; + +namespace xIdentityService.Providers +{ + public partial class XIdentityProvider + { + public async Task GetUserInfo( + XDeviceDto device, + string userSelectByParam + ) + { + // + // Validate Args ... + validationProvider.NotNull(device); + validationProvider.NotEmpty(userSelectByParam); + + // + // Prepare Open Action Model ... + var opaModel = new XOpenActionRequestDto + { + Device = device, + Payload = userSelectByParam, + Action = XOpenActions.GetUserInfo, + Timestamp = DateTime.UtcNow.AddMinutes(5) + }; + if (!opaModel.Validate()) + { + XException.InvalidArgs.Throw(); + } + + // + // Fill Checksum Filed ... + var token = opaModel.ToOpenActionToken(); + opaModel.Checksum = token; + + // + // Prepare Request ... + var opaJson = opaModel.ToJson(); + var requestString = SecurityProvider.Encrypt(opaJson); + + // + return await GetUserInfo( + token: token, + request: requestString + ); + } + + public async Task GetUserInfo(XOpenActionInnerDto dto) + { + // + return await GetUserInfo( + token: dto.Token, + request: dto.Payload + ); + } + + public async Task GetUserInfo( + string token, + string request + ) + { + // + // Validate Args ... + validationProvider.NotEmpty(token); + validationProvider.NotEmpty(request); + + // + // Retrieve Rest Client ... + var client = GetRestClient(); + + // + // Prepare Rest Request ... + var requestU = GetRestRequet( + XApiAccountEndpoint.GetUserInfo, + @params: new Dictionary + { + { XParam.XRequest.GetStringValue(), request } + }, + headers: new Dictionary + { + { XAuthentication.TOKEN, token} + } + ); + + // + var response = await RunRestRequestByResponse( + client, + requestU, + XHttpMethod.GET + ); + + // + // Now we Have to Validate the recieved response ... + + // + // Read token from Headers ... + + // + var responseToken = response.Response.Headers.First(h => h.Name == XAuthentication.TOKEN).ToString(); + if (responseToken.IsNullOrEmpty()) + { + XException.ActionFailed.Throw(); + } + + // + var responseJson = SecurityProvider.Decrypt(response.Model); + if (responseJson.IsNullOrEmpty()) + { + XException.ActionFailed.Throw(); + } + + // + // Retrieve Model and Validate it ... + var responseModel = responseJson.FromJSON(); + if (responseModel.IsNull() || + responseModel.Timestamp.IsExPired() || + responseModel.Payload.IsNullOrEmpty() || + // !responseModel.Device.IsSameAs(device) || + responseToken != responseModel.Checksum) + { + XException.ActionFailed.Throw(); + } + + // + // Try to Retrieve Model ... + var result = responseModel.Payload.FromJSON(); + + // + return result; + } + } +} \ No newline at end of file diff --git a/Providers/XIdentityProvider.cs b/Providers/XIdentityProvider.cs index d5c0db9..8dcbc12 100644 --- a/Providers/XIdentityProvider.cs +++ b/Providers/XIdentityProvider.cs @@ -21,6 +21,7 @@ using xIdentityModels.Models; using xIdentityService.Configuration; using xIdentityService.Constants; using xIdentityService.Interfaces; +using xIdentityService.Models; namespace xIdentityService.Providers { public partial class XIdentityProvider : IXIdentityProvider { @@ -30,16 +31,18 @@ namespace xIdentityService.Providers { private readonly XValidationProvider validationProvider; private readonly XIdentityServiceConfiguration identityConfiguration; + public ILogger Logger { get; } + public IXSecurityProvider SecurityProvider { get; } + public string BaseUrl { get; } public string RevisionSecretKey { get; } - public bool ReadResponseAsString { get; set; } - public ILogger Logger { get; } public XIdentityProvider ( IXTokenProvider tokenProvider, IHostingEnvironment environment, ILogger logger, + IXSecurityProvider securityProvider, XIdentityServiceConfiguration identityConfiguration, XValidationProvider validationProvider ) { @@ -50,6 +53,7 @@ namespace xIdentityService.Providers { // this.environment = environment; Logger = logger; + SecurityProvider = securityProvider; // this.identityConfiguration = identityConfiguration; @@ -345,6 +349,149 @@ namespace xIdentityService.Providers { // return response; } + public async Task> RunRestRequestByResponse ( + RestClient client, + RestRequest request, + XHttpMethod method, + bool supportRefreshingTokens = true + ) { + // + var response = await Task.Run (async () => { + // + IRestResponse resp = null; + + // + // Call Endpoint Service using Specified Method ... + switch (method) { + // + // Get ... + case XHttpMethod.GET: + resp = client.Get (request); + break; + + // + // Put ... + case XHttpMethod.PUT: + resp = client.Put (request); + break; + + // + // Post ... + case XHttpMethod.POST: + resp = client.Post (request); + break; + + // + // Delete ... + case XHttpMethod.DELETE: + resp = client.Delete (request); + break; + } + + // + if (!resp.IsSuccessful) { + // + // Log Exception ... + Logger.LogError ($"Error: {resp.ErrorMessage}"); + Logger.LogError ($"Exception: {resp.ErrorException.ToJSON()}"); + if (!resp.ErrorMessage.IsNullOrEmpty () && + resp.ErrorMessage.Contains ("timed out")) { + XException.Timeout.Throw (); + } + + // + // TODO: Check UnAuthorized Status here for + // Refresh Tokens or Issue Correct Exception ... + if (supportRefreshingTokens && + resp.StatusCode == System.Net.HttpStatusCode.Unauthorized) { + // + var isRefreshed = request.Parameters.Any (rp => + rp.Name == XParam.XIsRefreshed.GetStringValue () && + rp.Value.ToString ().ToNormalString () == true.ToJSON ()); + + // + Logger.LogInformation ($"isRefreshed: {isRefreshed}"); + + // + // Get Access Token ... + XTokenResponse tokens = null; + var accessToken = request.Parameters.FirstOrDefault (rp => + rp.Name.ToNormalString () == XAuthorization.Header.ToNormalString ()).Value.ToString (); + if (!accessToken.IsNullOrEmpty ()) { + // + accessToken = accessToken.Replace (XAuthorization.TokenIdentifier, ""); + + // + if (!accessToken.IsNullOrEmpty ()) { + tokens = await tokenProvider.RetrieveToken (accessToken); + } + } + + // + // Refresh Token and then re do request ... + if (!isRefreshed && + !accessToken.IsNullOrEmpty () && + !tokens.IsNull () && + tokens.IsRefreshable ()) { + // + request.AddHeader (XParam.XIsRefreshed.GetStringValue (), true.ToJSON ()); + + // + // Refreshe Tokens ... + var refreshedTokens = await RefreshTokens (tokens); + + // + // Renew Rest Client with Refreshed Tokens ... + var timeout = client.Timeout; + client = GetRestClient (refreshedTokens); + client.Timeout = Timeout.Infinite; + + // + // Do Request Again using renew Client ... + return await RunRestRequestByResponse ( + client: client, + request: request, + method: method + ); + } + } + + // + var ex = resp.Content.ToXError (); + if (!ex.IsNull ()) { + throw ex.ToException (); + } + + // + // UnAuthorized ... + if (resp.StatusCode == System.Net.HttpStatusCode.Unauthorized) { + XException.NotAuthorized.Throw (); + } + + // + // NotFound ... + if (resp.StatusCode == System.Net.HttpStatusCode.NotFound) { + XException.NotFound.Throw (); + } + + // + XException.ActionFailed.Throw (); + } + + // + var result = new XBaseRestResponse + { + Response = resp, + Model = resp.Content.FromJSON () + }; + + // + return result; + }); + + // + return response; + } /// /// Get User SelectBy Param