Var*_*n R 7 c# asp.net-authorization azure-active-directory asp.net-core-webapi
我已使用标准方式在 ASP.Net Core 6 中实现了 Azure AD 身份验证,并在控制器类顶部使用了 [Authorize] 属性。所有这些都工作正常。
builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration, "AzureAd");
Run Code Online (Sandbox Code Playgroud)
除了身份验证之外,我还尝试使用 TypeFilterAttribute 类构建自定义授权。代码片段如下:
public class CustomAuthorizeAttribute : TypeFilterAttribute
{
public CustomAuthorizeAttribute(params Roles[] roles) : base(typeof(CustomAuthorizeFilter))
{
Roles[] _roles = roles;
Arguments = new object[] { _roles };
}
}
public class CustomAuthorizeFilter : IAuthorizationFilter
{
private readonly Roles[] _roles;
private readonly IUserService _userService;
public CustomAuthorizeFilter(Roles[] roles, IUserService userService)
{
_roles = roles ?? throw new UnauthorizedAccessException("OnAuthorization : Missing role parameter");
_userService = userService;
}
public async void OnAuthorization(AuthorizationFilterContext context)
{
if (context != null && context.HttpContext != null &&
context.HttpContext.User != null &&
context.HttpContext.User.Identity != null)
{
string? userEmailId = context.HttpContext.User.Identity.Name;
if (string.IsNullOrEmpty(userEmailId))
{
context.Result = new ContentResult()
{
Content = "OnAuthorization : Invalid User : Email Id is not present",
StatusCode = 401
};
return;
}
var userDetails = await _userService.GetUserProfile(userEmailId);
if (userDetails == null)
{
context.Result = new ContentResult()
{
Content = "OnAuthorization : Invalid User : User does not exist",
StatusCode = 403
};
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法: 对于每个控制器操作方法,我想要可以访问 Api 的角色。在下面的代码片段中,Roles 是一个枚举。基本上,我正在尝试为每个 Api 实现基于角色的访问。
[CustomAuthorize(Roles.Admin1,Roles.Admin2)]
Run Code Online (Sandbox Code Playgroud)
问题: 正在调用 CustomAuthorizeAttribute。但是,控制器操作的调用与 CustomAuthorizeAttribute 中的身份验证无关。
我在这里缺少什么?
问题
问题在于方法本身,您正在使用对异步方法的调用
var userDetails = await _userService.GetUserProfile(userEmailId);
Run Code Online (Sandbox Code Playgroud)
这迫使您将方法签名更改为:
public async void OnAuthorization(AuthorizationFilterContext context)
Run Code Online (Sandbox Code Playgroud)
由于无法等待对此方法的调用(您无法将其更改为),因此框架永远不会在及时public async Task OnAuthorization(AuthorizationFilterContext context)
之后执行代码。未及时进行await
评估。if (userDetails == null)
通过提供脏修复来演示问题
如果你改变线路
var userDetails = await _userService.GetUserProfile(userEmailId);
Run Code Online (Sandbox Code Playgroud)
到
var userDetails = _userService.GetUserProfile(userEmailId).Result;
Run Code Online (Sandbox Code Playgroud)
您会注意到身份验证已正确执行。但是,使用.Result
不是最佳实践,也不建议使用。因此,要么更改GetUserProfile
为同步函数,要么使用支持基于任务的方法的授权机制,允许您正确等待方法。
解决方案
有一个IAsyncAuthorizationFilter
接口支持基于任务的方法,因此请使用该接口。只需要最少的代码更改:
var userDetails = await _userService.GetUserProfile(userEmailId);
Run Code Online (Sandbox Code Playgroud)
请注意:.Net Core 中引入了执行授权的新方法,请参阅文档。例如,您可以使用基于策略或基于角色的授权,它们本身也支持基于任务的方法,允许您在自定义策略中使用异步方法。
参考
归档时间: |
|
查看次数: |
1623 次 |
最近记录: |