[英]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:我尝试以下过程:
/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.