Skip to content

Instantly share code, notes, and snippets.

@hikalkan
Last active March 20, 2020 07:10
Show Gist options
  • Select an option

  • Save hikalkan/8862d9f7ae8b4874976d to your computer and use it in GitHub Desktop.

Select an option

Save hikalkan/8862d9f7ae8b4874976d to your computer and use it in GitHub Desktop.

Revisions

  1. hikalkan revised this gist Dec 29, 2015. No changes.
  2. hikalkan created this gist Dec 29, 2015.
    130 changes: 130 additions & 0 deletions AccountController.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,130 @@

    /* 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
    27 changes: 27 additions & 0 deletions ImpersonationCacheItem.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,27 @@
    [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;
    }
    }
    7 changes: 7 additions & 0 deletions ImpersonationCacheManagerExtensions.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    public static class ImpersonationCacheManagerExtensions
    {
    public static ITypedCache<string, ImpersonationCacheItem> GetImpersonationCache(this ICacheManager cacheManager)
    {
    return cacheManager.GetCache<string, ImpersonationCacheItem>(ImpersonationCacheItem.CacheName);
    }
    }