Last active
March 20, 2020 07:10
-
-
Save hikalkan/8862d9f7ae8b4874976d to your computer and use it in GitHub Desktop.
User Impersonation for ASP.NET Boilerplate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* SAMPLE AJAX CALL to this action: | |
(This is enough since it's automatically redirected to the target tenant's ImpersonateSignIn action) | |
abp.ajax({ | |
url: abp.appPath + 'Account/Impersonate', | |
data: JSON.stringify({ | |
tenantId: 1, //Target tenant id (can be null if target user is a host user) | |
userId: 2 //Target user id | |
}) | |
}); | |
*/ | |
[AbpMvcAuthorize(AppPermissions.Pages_Administration_Users_Impersonation)] | |
public virtual async Task<JsonResult> Impersonate(ImpersonateModel model) | |
{ | |
CheckModelState(); | |
if (AbpSession.ImpersonatorUserId.HasValue) | |
{ | |
throw new UserFriendlyException(L("CascadeImpersonationErrorMessage")); | |
} | |
if (AbpSession.TenantId.HasValue) | |
{ | |
if (!model.TenantId.HasValue) | |
{ | |
throw new UserFriendlyException(L("FromTenantToHostImpersonationErrorMessage")); | |
} | |
if (model.TenantId.Value != AbpSession.TenantId.Value) | |
{ | |
throw new UserFriendlyException(L("DifferentTenantImpersonationErrorMessage")); | |
} | |
} | |
return await SaveImpersonationTokenAndGetTargetUrl(model.TenantId, model.UserId, false); | |
} | |
[UnitOfWork] | |
public virtual async Task<ActionResult> ImpersonateSignIn(string tokenId) | |
{ | |
var cacheItem = await _cacheManager.GetImpersonationCache().GetOrDefaultAsync(tokenId); | |
if (cacheItem == null) | |
{ | |
throw new UserFriendlyException(L("ImpersonationTokenErrorMessage")); | |
} | |
//Switch to requested tenant | |
using (_unitOfWorkManager.Current.SetFilterParameter(AbpDataFilters.MayHaveTenant, AbpDataFilters.Parameters.TenantId, cacheItem.TargetTenantId)) | |
{ | |
//Get the user from tenant | |
var user = await _userManager.FindByIdAsync(cacheItem.TargetUserId); | |
//Create identity | |
var identity = await _userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); | |
if (!cacheItem.IsBackToImpersonator) | |
{ | |
//Add claims for audit logging | |
if (cacheItem.ImpersonatorTenantId.HasValue) | |
{ | |
identity.AddClaim(new Claim(AbpClaimTypes.ImpersonatorTenantId, cacheItem.ImpersonatorTenantId.Value.ToString(CultureInfo.InvariantCulture))); | |
} | |
identity.AddClaim(new Claim(AbpClaimTypes.ImpersonatorUserId, cacheItem.ImpersonatorUserId.ToString(CultureInfo.InvariantCulture))); | |
} | |
//Sign in with the target user | |
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie); | |
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = false }, identity); | |
//Remove the cache item to prevent re-use | |
await _cacheManager.GetImpersonationCache().RemoveAsync(tokenId); | |
return RedirectToAction("Index", "Application"); | |
} | |
} | |
/* SAMPLE AJAX CALL to this action: | |
(This is enough since it's automatically redirected to the host's ImpersonateSignIn action) | |
abp.ajax({ | |
url: abp.appPath + 'Account/BackToImpersonator' | |
}); | |
*/ | |
public virtual async Task<JsonResult> BackToImpersonator() | |
{ | |
if (!AbpSession.ImpersonatorUserId.HasValue) | |
{ | |
throw new UserFriendlyException(L("NotImpersonatedLoginErrorMessage")); | |
} | |
return await SaveImpersonationTokenAndGetTargetUrl(AbpSession.ImpersonatorTenantId, AbpSession.ImpersonatorUserId.Value, true); | |
} | |
private async Task<JsonResult> SaveImpersonationTokenAndGetTargetUrl(int? tenantId, long userId, bool isBackToImpersonator) | |
{ | |
//Create a cache item | |
var cacheItem = new ImpersonationCacheItem( | |
tenantId, | |
userId, | |
isBackToImpersonator | |
); | |
if (!isBackToImpersonator) | |
{ | |
cacheItem.ImpersonatorTenantId = AbpSession.TenantId; | |
cacheItem.ImpersonatorUserId = AbpSession.GetUserId(); | |
} | |
//Create a random token and save to the cache | |
var tokenId = Guid.NewGuid().ToString(); | |
await _cacheManager | |
.GetImpersonationCache() | |
.SetAsync(tokenId, cacheItem, TimeSpan.FromMinutes(1)); | |
//Find tenancy name | |
string tenancyName = null; | |
if (tenantId.HasValue) | |
{ | |
tenancyName = (await _tenantManager.GetByIdAsync(tenantId.Value)).TenancyName; | |
} | |
//Create target URL | |
var targetUrl = _webUrlService.GetSiteRootAddress(tenancyName) + "Account/ImpersonateSignIn?tokenId=" + tokenId; | |
return Json(new MvcAjaxResponse { TargetUrl = targetUrl }); | |
} | |
#endregion |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Serializable] | |
public class ImpersonationCacheItem | |
{ | |
public const string CacheName = "AppImpersonationCache"; | |
public int? ImpersonatorTenantId { get; set; } | |
public long ImpersonatorUserId { get; set; } | |
public int? TargetTenantId { get; set; } | |
public long TargetUserId { get; set; } | |
public bool IsBackToImpersonator { get; set; } | |
public ImpersonationCacheItem() | |
{ | |
} | |
public ImpersonationCacheItem(int? targetTenantId, long targetUserId, bool isBackToImpersonator) | |
{ | |
TargetTenantId = targetTenantId; | |
TargetUserId = targetUserId; | |
IsBackToImpersonator = isBackToImpersonator; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class ImpersonationCacheManagerExtensions | |
{ | |
public static ITypedCache<string, ImpersonationCacheItem> GetImpersonationCache(this ICacheManager cacheManager) | |
{ | |
return cacheManager.GetCache<string, ImpersonationCacheItem>(ImpersonationCacheItem.CacheName); | |
} | |
} |
Please do u know how I can impersonate from a background job?
If you are asking for AspNet Boilerplate, see https://aspnetboilerplate.com/Pages/Documents/Abp-Session#overriding-current-session-values
public class MyService
{
private readonly IAbpSession _session;
public MyService(IAbpSession session)
{
_session = session;
}
public void Test()
{
using (_session.Use(42, null))
{
var tenantId = _session.TenantId; //42
var userId = _session.UserId; //null
}
}
}
Hi, I have two different test site on Azure. When I click "Login as this user" or "Login as this tenant" on second site (for example testsite2.azurewebsites.net), Impersonate method returns the first sites url (testsite1.azurewebsites.net/Account/ImpersonateSignIn?tokenId=" + tokenId) and I get error like "Impersonation token is invalid or expired". This only happens on second site. First site is working as expected. I did not change anything on Account/Impersonate method.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
I was trying to implement user impersonation. Couldn't find the ImpersonateModel class. Please could you suggest how to get it. Am I missing any reference?