简体   繁体   English

通过 HTTP 标头模拟用户

[英]User impersonation through HTTP header

I need to implement user impersonation through a HTTP header.我需要通过 HTTP 标头实现用户模拟。 For example, a user will send a request to /api/something with the header impersonate=someUser .例如,用户将使用标题impersonate=someUser/api/something发送请求。

I tried to following process:我尝试以下过程:

  1. User gets authenticated by one of multiple authentication schemes.用户通过多种身份验证方案之一进行身份验证。
  2. The authenticated user gets replaced by the impersonated user, if it passes some security checks.如果通过一些安全检查,经过身份验证的用户将被模拟用户替换。
  3. The /api/something endpoint is called /api/something端点被称为

I wrote some custom middleware for this, that runs just after the builtin authentication middelware:我为此编写了一些自定义中间件,它在内置身份验证中间件之后运行:

if (!context.Request.Headers.TryGetValue("%Impersonation header%", out StringValues subject))
{
    await _next(context);
    return;
}

if (context.User?.Identity?.IsAuthenticated != true)
{
    // return error
}

...

context.User = impersonatedUser
await _next(context);

However, when it finally reaches the controller, the initial user is still used because the ClaimsPrincipal has been replaced by the default authorization into a new object with two identities.但是,当它最终到达控制器时,仍然使用初始用户,因为ClaimsPrincipal已被默认授权替换为具有两个身份的新对象。 The first identity is the real user, the second identity is the impersonated user.第一个身份是真实用户,第二个身份是模拟用户。

I could potentially resolve the user then using the second identity, but I'm not sure this process is following best practices?我可以潜在地解析用户然后使用第二个身份,但我不确定这个过程是否遵循最佳实践?

Edit: this is for ASP.NET Core 2.2 / 3.1编辑:这是针对 ASP.NET Core 2.2 / 3.1

configure IISServerOptions in Startup.cs在 Startup.cs 中配置 IISServerOptions

services.AddAuthentication(IISDefaults.AuthenticationScheme);
        services.AddSimpleRoleAuthorization<CustomWindowsAuthenticationProvider>();
        services.Configure<IISServerOptions>(opt=>{
            opt.AutomaticAuthentication=true;
            opt.AuthenticationDisplayName="SIMS";
        });

then implement your own IClaimsTransformation to validate the user and set the claims apropriately然后实现您自己的 IClaimsTransformation 以验证用户并适当地设置声明

public class CustomWindowsAuthenticationProvider : ISimpleRoleProvider
{
    public CustomWindowsAuthenticationProvider(UnitOfWork unitOfWork)
    {
        this._unitOfWork = unitOfWork;
    }
    private UnitOfWork _unitOfWork;

    public Task<ICollection<string>> GetUserRolesAsync(string userName)
    {
        ICollection<string> result = new string[0];
        string[] user = userName.Split("\\");
        var roles = _unitOfWork.UserMod.GetRolesForUser(user[1]);
        if (roles!=null)
            result = roles.Select(d => d.RoleName).ToArray();


        return Task.FromResult(result);
    }
}
public interface ISimpleRoleProvider
{
    #region Public Methods

    /// <summary>
    /// Loads and returns the role names for a given user name.
    /// </summary>
    /// <param name="userName">The login name of the user for which to return the roles.</param>
    /// <returns>
    /// A collection of <see cref="string" /> that describes the roles assigned to the user;
    /// An empty collection of no roles are assigned to the user.
    /// </returns>
    /// <remarks>
    ///     <para>Beware that this method is called for each controller call. It might impact performance.</para>
    ///     <para>
    ///     If Windows authentication is used, the passed <paramref name="userName" />
    ///     is the full user name including the domain or machine name (e.g "CostroDomain\JohnDoe" or
    ///     "JOHN-WORKSTATION\JohnDoe").
    ///     </para>
    ///     <para>
    ///     The returned roles names can be used to restrict access to controllers using the <see cref="AuthorizeAttribute" />
    ///     (<c>[Authorize(Roles="...")]</c>
    ///     </para>
    /// </remarks>
    Task<ICollection<string>> GetUserRolesAsync(string userName);

    #endregion
}
public class SimpleRoleAuthorizationTransform : IClaimsTransformation
{
    #region Private Fields

    private static readonly string RoleClaimType = ClaimTypes.Role;//  $"http://{typeof(SimpleRoleAuthorizationTransform).FullName.Replace('.', '/')}/role";
    private readonly ISimpleRoleProvider _roleProvider;

    #endregion

    #region Public Constructors

    public SimpleRoleAuthorizationTransform(ISimpleRoleProvider roleProvider)
    {
        _roleProvider = roleProvider ?? throw new ArgumentNullException(nameof(roleProvider));
    }

    #endregion

    #region Public Methods

    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        // Cast the principal identity to a Claims identity to access claims etc...
        var oldIdentity = (ClaimsIdentity)principal.Identity;

        // "Clone" the old identity to avoid nasty side effects.
        // NB: We take a chance to replace the claim type used to define the roles with our own.
        var newIdentity = new ClaimsIdentity(
            oldIdentity.Claims,
            oldIdentity.AuthenticationType,
            oldIdentity.NameClaimType,
            RoleClaimType);

        // Fetch the roles for the user and add the claims of the correct type so that roles can be recognized.
        var roles = await _roleProvider.GetUserRolesAsync(newIdentity.Name);
        if(roles.Count>0)
            newIdentity.AddClaims(roles.Select(r => new Claim(RoleClaimType, r)));

        // Create and return a new claims principal
        return new ClaimsPrincipal(newIdentity);
    }

    #endregion
}
public static class SimpleRoleAuthorizationServiceCollectionExtensions
{
    #region Public Static Methods

    /// <summary>
    /// Activates simple role authorization for Windows authentication for the ASP.Net Core web site.
    /// </summary>
    /// <typeparam name="TRoleProvider">The <see cref="Type"/> of the <see cref="ISimpleRoleProvider"/> implementation that will provide user roles.</typeparam>
    /// <param name="services">The <see cref="IServiceCollection"/> onto which to register the services.</param>
    public static void AddSimpleRoleAuthorization<TRoleProvider>(this IServiceCollection services)
        where TRoleProvider : class, ISimpleRoleProvider
    {
        services.AddScoped<ISimpleRoleProvider, TRoleProvider>();
        services.AddScoped<IClaimsTransformation, SimpleRoleAuthorizationTransform>();
    }

    #endregion
}

after that you can host the app in iis, and use the iis authentication to determine what kind of method and settings you want to use.之后你可以在iis中托管应用程序,并使用iis身份验证来确定你想要使用什么样的方法和设置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM