【发布时间】:2019-11-06 20:48:12
【问题描述】:
我希望能够直接在控制器的参数中提供当前用户的声明。这样我就可以在不触及 ClaimPrincipal 魔法的情况下编写单元测试。
像 [FromUri] 或 [FromBody],也许是 [FromClaim]?
我尝试按照 Microsoft 的以下文档中的说明实现 CustomModelProvider:https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-2.2
但我不知道如何提供 ClaimsPrincipal 或 List。 ValueProvider 也返回一个字符串,所以我不确定这实际上是否可行。
这是我对 ClaimModelBinder 的尝试
public class ClaimModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext));
var modelName = bindingContext.ModelName;
// Try to fetch the value of the argument by name
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask;
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
// TODO: Unsure, how to continue after this.
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value)) return Task.CompletedTask;
int id = 0;
if (!int.TryParse(value, out id))
{
// Non-integer arguments result in model state errors
bindingContext.ModelState.TryAddModelError(
modelName,
"Author Id must be an integer.");
return Task.CompletedTask;
}
// Model will be null if not found, including for
// out of range id values (0, -3, etc.)
bindingContext.Result = ModelBindingResult.Success(null);
return Task.CompletedTask;
}
}
【问题讨论】:
-
从顶部的描述来看,这听起来有点像 XY 场景,您正在尝试使用旨在解决不同问题的解决方案来解决一个问题。 ClaimsPrincipal 中没有“魔法”,实际上构建一个 ClaimsPrincipal 进行测试比您在这里尝试做的要容易和正确得多。如果您真的想完成上述操作,您可以注入
IHttpContextAccessor并访问与请求关联的主体,但这是在操作中键入User.Claims的一种迂回方式 -
嗯,我虽然将系统相关的依赖项移动到参数是一种摆脱这种情况的方法。由于一直使用 DateTime 弹出依赖项有助于使单元测试更加清晰。您能否提供“构建用于测试的 ClaimsPrincipal 比您尝试做的更容易、更正确”的来源?
标签: c# asp.net-core .net-core jwt asp.net-core-webapi