• 从零开始Blazor Server(6)--基于策略的权限验证


    现在BootstrapBlazor处于大更新时期,Menu组件要改为泛型模式。

    本来我们的这一篇应该是把Layout改了,但是改Layout肯定要涉及到菜单,如果现在写了呢,就进入一个发布就过时的状态,就很尴尬,所以后面的就稍微拖一拖。

    加上昨天有人说我用OnNavigateAsync违反单一性原则,要用策略,所以这里我们说下策略怎么做。

    添加策略相关的代码

    首先我们要有一个实现IAuthorizationRequirement接口的类,这个类没有什么特别的要求,我们就写一个空类来处理。

    1. public class AdminRequirement : IAuthorizationRequirement
    2. {
    3. }

    然后要写一个Handler,来继承这个AuthorizationHandler,其中泛型是我们上面的实现接口的类。

    1. public class AdminRequirementHandler : AuthorizationHandler<AdminRequirement>
    2. {
    3. protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdminRequirement requirement)
    4. {
    5. context.Succeed(requirement);
    6. return Task.CompletedTask;
    7. }
    8. }

    实现HandleRequirementAsync方法,这个方法就是我们的关键方法,授权的实现就在这里面。

    其中默认的授权状态是Fail,如果我们希望允许通过,就执行context.Succeed(requirement);来告诉策略我们认证成功了。

    添加授权认证

    Program.cs里我们需要把这两个都注册进去,首先注册我们的Handler

    builder.Services.AddSingleton<IAuthorizationHandler, AdminRequirementHandler>();

    然后注册我们的授权策略

    1. builder.Services.AddAuthorization(options =>
    2. {
    3. options.AddPolicy("Admin", policy => policy.Requirements.Add(new AdminRequirement()));
    4. });

    这里的Admin就是我们的策略名字。

    使用策略

    在我们需要认证的位置增加特性@attribute [Authorize(Policy = "Admin")],然后在我们的授权策略里打断点,应该就会发现断点进入了。

    将RouteData传入

    因为Blazor里面我们拿不到HttpContext,所以没法用Request.Path的方式来拿到url,所以只能使用将RouteData作为Resource传入,然后使用attribute的方式拿到。

    这里我们在App.razor里传入routeData

    1. <AuthorizeRouteView Resource="@routeData" RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
    2. <NotAuthorized>
    3. <RedirectToLogin></RedirectToLogin>
    4. </NotAuthorized>
    5. </AuthorizeRouteView>

    然后修改HandleRequirementAsync

    1. if (context.User.Identity?.IsAuthenticated != true)
    2. {
    3. return Task.CompletedTask;
    4. }
    5. if (!int.TryParse(context.User.FindFirst(ClaimTypes.Role)?.Value, out var roleId))
    6. {
    7. return Task.CompletedTask;
    8. }
    9. if (context.Resource is RouteData routeData)
    10. {
    11. var routeAttr = routeData.PageType.CustomAttributes.FirstOrDefault(x =>
    12. x.AttributeType == typeof(RouteAttribute));
    13. if (routeAttr == null)
    14. {
    15. context.Succeed(requirement);
    16. }
    17. else
    18. {
    19. var url = routeAttr.ConstructorArguments[0].Value as string;
    20. var permission = PermissionEntity
    21. .Where(x => x.Roles!.Any(y => y.Id == roleId) && x.Url == url).First();
    22. if (permission != null)
    23. {
    24. context.Succeed(requirement);
    25. }
    26. }
    27. }
    28. return Task.CompletedTask;
    29. }

    这里跟上一篇的处理思路整体一样,首先我们判断如果用户都没登录,那就直接失败,如果登录了我们就去拿RoleId,拿不到自然就失败。

    不同点在下面,我们没法直接拿到Path,所以我们只能去找RouteAttribute,其实就是我们的@page路由。这里我们也可以自己定义一个Attribute取自己的。

    如果我们没找到这个,证明这应该不是个blazor页面,我们就暂时让它成功。

    如果找到了,那么我们就找routeAttr.ConstructorArguments[0].Value as string,这里面就是对应的路由地址了。

    下面就跟之前一样,用路由地址来判断是否是又权限就行了。

  • 相关阅读:
    七牛云配置自定义域名
    离线升级esp32开发板升级包esp32-2.0.14(最新版已经3.0alpha了)
    开发常用的信息核验类API强烈推荐
    “山大地纬杯”第十二届山东省ICPC大学生程序设计竞赛
    快乐数(C++解法)
    【Tensorflow 2.12 电影推荐项目搭建】
    机器学习——线性回归
    【国庆头像】来一波美女国庆头像 超好看
    【Hack The Box】linux练习-- Blunder
    数据可视化在商业领域有哪些重要性?
  • 原文地址:https://blog.csdn.net/jh035/article/details/127998973