冒充用户在 JWT 中嵌入了错误的详细信息

Impersonating user embeds wrong details inside JWT

我正在使用以下服务获取 JWT 令牌来模拟用户。

[Authenticate]
[RequiredRole(nameof(UserRoles.Admin))]
public class ImpersonateUserService : Service
{
    private static ILog Log = LogManager.GetLogger(typeof(ImpersonateUserService));

    public ImpersonateUserResponse Any(ImpersonateUserRequest request)
    {
        var user = Db.SingleById<UserAuthCustom>(request.UserId);

        using (var service = base.ResolveService<AuthenticateService>()) //In Process
        {
            var resp = service.PostAsync(new Authenticate
            {
                provider = AuthenticateService.CredentialsProvider,
                UserName = user.UserName ?? user.Email,
                UseTokenCookie = true, // if using JWT
            }).Result;

            var token = ((AuthenticateResponse)resp).BearerToken;

            return new ImpersonateUserResponse()
            {
                Success = true,
                Token = token,
                Email = user.Email,
                DisplayName = user.DisplayName,
                UserId = user.Id,
                UserRole = (UserRoles)Enum.Parse(typeof(UserRoles), user.Roles[0]),
                UserName = user.UserName ?? user.Email
            };
        }
    }
}

public class ImpersonateUserRequest : IReturn<ImpersonateUserResponse>
{
    public int UserId { get; set; }
}

public class ImpersonateUserResponse : ApiMessage
{
    public string Token { get; set; }
    public string Email { get; set; }
    public string DisplayName { get; set; }
    public string UserName { get; set; }
    public int UserId { get; set; }
    public UserRoles UserRole { get; set; }
}

问题是,当使用令牌时,它会激活管理员详细信息而不是模拟用户。如果我解码模拟令牌,我可以看到:

{
  "sub": 1,
  "iat": 1623677160,
  "exp": 1624886760,
  "email": "email@example.com",
  "given_name": "admin name",
  "name": "admin name",
  "roles": [
    "Admin"
  ],
  "jti": 9
}

此令牌将允许我根据模拟用户角色访问端点(即根据“用户”角色而不是管理员身份验证的端点),但会在请求时带回管理员详细信息SessionAs<CustomUserSession>

获取包含正确详细信息的令牌的最佳方法是什么?

将回答我自己的问题,因为文档建议模拟用户不会模拟会话。

为了让它工作,我必须在模拟端点中完全创建 JWT

var user = Db.SingleById<UserAuthCustom>(request.UserId);

var customSession = new CustomUserSession()
{
    UserAuthId = user.Id.ToString(),
    UserName = user.UserName,
    DisplayName = user.DisplayName,
    Email = user.Email,
    IsAuthenticated = true,
    Roles = user.Roles
};

var jwtProvider = new JwtAuthProvider(Settings)
{
    AuthKeyBase64 = Settings.GetString("auth:key")
};

var header = JwtAuthProvider.CreateJwtHeader(jwtProvider.HashAlgorithm);
var body = JwtAuthProvider.CreateJwtPayload(
    customSession,
    issuer: jwtProvider.Issuer,
    expireIn: jwtProvider.ExpireTokensIn,
    roles: user.Roles
);

var jwtToken = JwtAuthProvider.CreateJwt(header, body, jwtProvider.GetHashAlgorithm());

return new ImpersonateUserResponse()
{
    Success = true,
    Token = jwtToken,
    Email = user.Email,
    DisplayName = user.DisplayName,
    UserId = user.Id,
    UserRole = (UserRoles)Enum.Parse(typeof(UserRoles), user.Roles[0]),
    UserName = user.UserName ?? user.Email
};