有三组Api(或页面),使用不同的授权方案,要求彼此独立,但默认只有授权方案只有一个。
需要授权的api(或页面)好解决,使用Authorize(AuthenticationSchemes = "")在对应的控制器、方法、Razor Pages标注就可以了。
但是对于不需要授权的api(或页面)且不是默认授权方案的,怎么确保 HttpContext.User 获取到的是当前Api(或页面)所在授权方案内中获取的 User 信息。
举个栗子:
三组接口或api:A组页面使用Cookie授权方案,B组Api使用自定义授权方案,C组Api使用JwtBearer授权方案,A、B、C互不兼容,且A、B、C组内都分别有需要授权的和不需要授权的接口(或页面)。
假设A1、B1、C1是需要授权的,A2、B2、C2是不需要授权就能访问的。
历史原因,需优先确保B组接口正常,因为B组Api接口在大量使用中,接口众多且不好修改,能不动就不动,只能设置成默认的授权方案(即自定义的授权方案),杜绝出现B2接口内部识别不了当前请求用户的情况。
现在的问题是:
A2页面顶部有个导航条需要显示当前登录的用户名,因为这个页面不需要授权,即不能使用Authorize(AuthenticationSchemes = "") 标注,也就没法区分这个页面到底属于那组,那么只能取默认的,即这个页面内 HttpContext.User 获取到的是B组的登录凭证。
你看看是否可以这样实现
ABC各定义一组授权标注,在需要授权的PAI加上对应的注解即可,不需要授权的PAI加上AllowAnonymous注解即可。
在授权方案中,首先是检索是否有不授权注解,如果有,那么直接返回,大概代码如下:
/// <summary>
/// A授权认证过滤器
/// </summary>
public class AAuthFilterAttribute : AuthorizationFilterAttribute
{
/// <summary>
/// 认证授权验证
/// </summary>
/// <param name="actionContext">请求上下文</param>
public override void OnAuthorization(HttpActionContext actionContext)
{
// 有 AllowAnonymous 属性的接口直接开绿灯
if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
{
return;
}
// 对应A的授权逻辑,自己实现
}
}
/// <summary>
/// B授权认证过滤器
/// </summary>
public class BAuthFilterAttribute : AuthorizationFilterAttribute
{
/// <summary>
/// 认证授权验证
/// </summary>
/// <param name="actionContext">请求上下文</param>
public override void OnAuthorization(HttpActionContext actionContext)
{
// 有 AllowAnonymous 属性的接口直接开绿灯
if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
{
return;
}
// 对应B的授权逻辑,自己实现
}
}
/// <summary>
///C授权认证过滤器
/// </summary>
public class CAuthFilterAttribute : AuthorizationFilterAttribute
{
/// <summary>
/// 认证授权验证
/// </summary>
/// <param name="actionContext">请求上下文</param>
public override void OnAuthorization(HttpActionContext actionContext)
{
// 有 AllowAnonymous 属性的接口直接开绿灯
if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any())
{
return;
}
// 对应C的授权逻辑,自己实现
}
}
是可以这样实现,引起这个bug的原因就是 AuthorizeAttribute 可以指定 AuthenticationSchemes AllowAnonymousAttribute 却没有对应的参数可以区分
引起这个的原因就是默认系统只能有一个默认的 AuthenticationScheme,在 AuthenticationMiddleware 未显示用 AuthorizeAttribute 指定 AuthenticationSchemes 时,它就取的是默认的。
修复方法就是,重写 HttpContext.User,用你的这种方式也行,直接写在业务逻辑前也可以。
// 在A2页面 OnGet 最前面加上如下代码即可
var result = await this.HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
if (result?.Principal != null)
{
this.HttpContext.User = result.Principal;
}
不知道这个算不算是一个bug