当前位置: 首页 > news >正文

在 .NET Core 中实现基于策略和基于角色的授权

本文主要介绍如何使用 .NET Core 实现基于策略的授权。 如果您需要了解授权技术的基础知识,请参阅链接。让我们来分解一下关键组件:

1、身份验证设置

    • 首先,在您的应用程序中设置身份验证。这可确保正确识别和验证用户身份。
    • 您通常会使用第三方身份验证提供程序(如 Microsoft Identity Platform)来处理用户登录和颁发令牌。

2、授权策略

    • 接下来,定义授权策略。这些策略决定谁可以访问应用程序的特定部分。
    • 策略可以很简单(例如“仅限经过身份验证的用户”),也可以更复杂(基于声明、角色或自定义要求)。

3、默认策略

    • 创建一个适用于所有端点的默认策略,除非被覆盖。
    • 例如,您可能要求用户经过身份验证并具有特定声明(如首选用户名)。

4、自定义策略

    • 为特定场景添加自定义策略。这些策略允许对访问进行细粒度的控制。
    • 例如,您可以根据权限创建策略(例如“创建/编辑用户”或“查看用户”)。

5、权限要求

    • 定义权限要求(例如 PermissionAuthorizationRequirement)。这些代表特定的操作或功能。
    • 对于每个要求,检查用户是否具有必要的权限(基于其角色或其他标准)。

6、基于角色的授权

    • 可选地,合并基于角色的授权。
    • 角色将具有相似访问级别的用户分组(例如,“管理员”、“用户”等)。您可以将角色分配给用户。

7、授权处理程序

    • 实施自定义授权处理程序(例如 AuthorizationHandler)。
    • 这些处理程序评估用户是否满足要求(例如,具有正确的权限或角色)。

8、控制器动作

    • 在控制器操作中,应用授权规则。
    • 使用 [Authorize] 具有策略或角色的属性。

9、中间件结果处理

    • 自定义如何处理授权结果(例如,401 未授权或 403 禁止响应)。
    • 您可以创建一个 AuthorizationMiddlewareResultHandler 来管理此行为

让我们继续进行 Web API 的实际编码:

Program.cs: 按原样使用 Azure AD 身份验证。确定授权的权限密钥。

AddPolicy 方法中只有一个策略

//In Program.cs file, add the below code

            var builder = WebApplication.CreateBuilder(args);

            // Authentication using Microsoft Identity Platform
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

            // Default policy-based authorization
            services.AddAuthorizationCore(options =>
            {
                options.DefaultPolicy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .RequireClaim("preferred_username")
                    .RequireScope("user_impersonation")
                    .Build();

                options.AddPolicy("Permission1", policy =>
                    policy.Requirements.Add(new PermissionAuthorizationRequirement("Permission1")));

                options.AddPolicy("Permission2", policy =>
                    policy.Requirements.Add(new PermissionAuthorizationRequirement("Permission2")));
            });

            // Authorization handler
            services.AddScoped<IAuthorizationHandler, AuthorizationHandler>();

            // Middleware result handler for response errors (401 or 403)
            services.AddScoped<IAuthorizationMiddlewareResultHandler, AuthorizationMiddlewareResultHandler>();

            // Other services and configurations...

PermissionAuthorizationRequirement .cs: 只需复制并粘贴要求

//Create new PermissionAuthorizationRequirement.cs file for Custom requirement for permission-based authorization
    public class PermissionAuthorizationRequirement : IAuthorizationRequirement
    {
        public PermissionAuthorizationRequirement(string allowedPermission)
        {
            AllowedPermission = allowedPermission;
        }

        public string AllowedPermission { get; }
    }

AuthorizationHandler.cs:( 只需复制并粘贴代码。确保使用应用程序管理器点击 DB 调用以获取权限列表)

// Custom authorization handler to check user permissions
    public class AuthorizationHandler : AuthorizationHandler<PermissionAuthorizationRequirement>
    {
        // Business layer service for user-related operations
        private readonly IAppManager _appManager;

        public AuthorizationHandler(IAppManager appManager)
        {
            _appManager= appManager;
        }

        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement)
        {
            // Find the preferred_username claim
            var preferredUsernameClaim = context.User.Claims.FirstOrDefault(c => c.Type == "preferred_username");

            if (preferredUsernameClaim is null)
            {
                // User is not authenticated
                context.Fail(new AuthorizationFailureReason(this, "UnAuthenticated"));
                return;
            }

            // Call the business layer method to check if the user exists
            var user = await _appManager.GetUserRolesAndPermissions(preferredUsernameClaim);

            if (user is null || !user.IsActive)
            {
                // User does not exist or is inactive
                context.Fail(new AuthorizationFailureReason(this, "UnAuthenticated"));
                return;
            }

            // Select the list of permissions that the user is assigned
            // Here you will fetch the Permission1 and Permission2
            var userPermissions = user.UserPermissions?.Select(k => k.PermissionKey);

            // Get the current permission key from the controller's action method
            string allowedPermission = requirement.AllowedPermission;


            // Check if the current request carries this permission
            if (userPermissions.Any(permission => permission == allowedPermission))
            {
                // Permission granted
                context.Succeed(requirement);
                return;
            }

            // Permission denied
            context.Fail();
        }
    }

AuthorizationMiddlewareResultHandler.cs: 只需复制粘贴即可。无需任何更改。

// AuthorizationMiddlewareResultHandler to decide response code (401 or success)
public class AuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
    private readonly ILogger<AuthorizationMiddlewareResultHandler> _logger;
    private readonly Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler _defaultHandler = new();

    public AuthorizationMiddlewareResultHandler(ILogger<AuthorizationMiddlewareResultHandler> logger)
    {
        _logger = logger;
    }

    public async Task HandleAsync(
        RequestDelegate next,
        HttpContext context,
        AuthorizationPolicy policy,
        PolicyAuthorizationResult authorizeResult)
    {
        var authorizationFailureReason = authorizeResult.AuthorizationFailure?.FailureReasons.FirstOrDefault();
        var message = authorizationFailureReason?.Message;

        if (string.Equals(message, "UnAuthenticated", StringComparison.CurrentCultureIgnoreCase))
        {
            // Set response status code to 401 (Unauthorized)
            context.Response.StatusCode = "401";
            _logger.LogInformation("401 failed authentication");
            return;
        }

        // If not unauthorized, continue with default handler
        await _defaultHandler.HandleAsync(next, context, policy, authorizeResult);
    }
}

Controller.cs: 最后,在仪表板控制器中添加 [Authorize] 和 [Policies] 属性。这里定义Permission1和Permission2。

// Dashboard controller
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class DashboardController : ControllerBase
{
    [HttpGet]
    [Route("get-dashboardDetails")]
    [Authorize(Policy = "Permission1")]
    public async Task GetAllDashboardDetailsAsync()
    {
        // Your logic for fetching all user details
        return await GetAllDashboardDetailsAsync();
    }

    [HttpGet]
    [Route("create-product")]
    [Authorize(Policy = "Permission2")]
    //[Authorize(Policy = nameof(Read string from ENUM))]
    public async Task CreateProductAsync([FromBody] Product product)
    {
        // Your logic for creating a new product
    }
}

现在,如果您想在 Web API 代码中结合使用基于角色的授权,请按照以下步骤操作,或者您也可以跳过此步骤。它与我们基于策略的授权的步骤几乎相同,只有一些细微的差别,您可以在代码中发现。

一. 注册 RoleAuthorizationHandler

在您的 Program.cs 文件中,只需添加以下行即可注册 RoleAuthorizationHandler

builder.Services.AddScoped<IAuthorizationHandler, RoleAuthorizationHandler>();

二.  RoleAuthorizationHandler

下面是 RoleAuthorizationHandler.cs 检查用户是否具有所需角色的处理器。再创建一个处理器 

public class RoleAuthorizationHandler : AuthorizationHandler<RolesAuthorizationRequirement>
{
    private readonly IAppManager _appManager;

    public RoleAuthorizationHandler(IAppManager appManager)
    {
        _appManager= appManager;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RolesAuthorizationRequirement requirement)
    {
        // Find the preferred_username claim
        Claim claim = context.User.Claims.FirstOrDefault(c => c.Type == "preferred_username");

        if (claim is not null)
        {
            // Get user details
            var userRoles = await _appManager.GetUserRolesAndPermissions(claim.Value);

            // Check if the user's roles match the allowed roles
            var roles = requirement.AllowedRoles;
            if (userRoles .Any(x => roles.Contains(x)))
            {
                context.Succeed(requirement); // User has the required roles
            }
            else
            {
                context.Fail(); // User does not have the required roles
                return;
            }
        }
        await Task.CompletedTask;
    }
}

三. 在 DashboardController 中的使用

在你的 DashboardController 中DashboardController,你可以同时使用角色和策略进行授权。例如:

[HttpGet]
[Route("get-dashboardDetails")]
[Authorize(Roles = "Super_Admin, Role_Administrator")] // Can have multiple roles. You can choose either Roles or Policy or both
[Authorize(Policy = "Permission1")] // Can have only one policy per action to accept.
public async Task GetAllDashboardDetailsAsync()
{
    // Your logic for fetching all user details
    return await GetAllDashboardDetailsAsync();
}

就这样。你的 Web API 将会像魔法一样运行。:-)。 

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。 

http://www.xdnf.cn/news/1399735.html

相关文章:

  • HarmonyOS应用的多Module设计机制:构建灵活高效的应用程序
  • 【瑞吉外卖】手机号验证码登录(用QQ邮件发送代替)
  • python制作一个股票盯盘系统
  • NV032NV037美光固态闪存NV043NV045
  • 基于开源AI大模型AI智能名片S2B2C商城小程序的产地优势产品销售策略研究
  • 前端代码结构详解
  • 盛最多水的容器,leetCode热题100,C++实现
  • 封装哈希表
  • 基于SpringBoot的流浪动物领养系统【2026最新】
  • macOS 15.6 ARM golang debug 问题
  • Rust Web 模板技术~MiniJinja入门:一款适用于 Rust 语言的轻依赖强大模板引擎
  • Fourier 级数展开(案例:级数展开 AND 求和)
  • Prompt Engineering:高效构建智能文本生成的策略与实践
  • 单例模式的mock类注入单元测试与友元类解决方案
  • Android15适配16kb
  • ros2 foxy没有话题问题解决
  • Axios 实例配置指南
  • Keil5 MDK_541官网最新版下载、安装
  • 从 0 到 1 构建零丢失 RabbitMQ 数据同步堡垒:第三方接口数据零丢失的终极方案
  • comfUI背后的技术——VAE
  • 线性代数理论——状态空间
  • 聊一聊耳机串扰-Crosstalk
  • Vue常用指令和生命周期
  • 118、【OS】【Nuttx】【周边】效果呈现方案解析:作用域?
  • 生成一份关于电脑电池使用情况、健康状况和寿命估算的详细 HTML 报告
  • 软考中级习题与解答——第一章_数据结构与算法基础(2)
  • 【Redisson 加锁源码解析】
  • VuePress添加自定义组件
  • 【MySQL数据库】索引 - 结构 学习记录
  • 加速智能经济发展:如何助力“人工智能+”战略在实时视频领域的落地