7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC

一、ABAC 简介

ABAC 即:【Attribute-based Access Control】基于属性的访问控制
与之对应的,我们有:【Role-based Access Control 】
可以参考这篇文章权限系统设计模型分析(DAC,MAC,RBAC,ABAC)
此处不再详细说明

7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC_第1张图片
image.png

二、Client 使用 ABAC

  1. 修改 IDP
  • Config

GetIdentityResources方法添加代码

new IdentityResource("country","Country where the user lives in", new List(){"country"}),
new IdentityResource("subscriptionlevel","User's subscription level",new List(){"subscriptionlevel"})

GetClients方法中的 AllowedScopes添加

7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC_第2张图片
image.png

GetUsers 方法中为 Users 添加对应 claim 和 值

  1. 修改 Client
  • Startup
    ConfigureServices方法修改如下:
    添加代码
            services.AddAuthorization(authorizationOptions =>
            {
                authorizationOptions.AddPolicy(
                    "CanOrderFrame",
                    policyBuilder =>
                    {
                        policyBuilder.RequireAuthenticatedUser();
                        policyBuilder.RequireClaim("country", "Heaven", "CHN");
                        policyBuilder.RequireClaim("subscriptionlevel", "supervip");
                    });
            });

定义一个 Policy:已登录用户并且付费级别为 supervip、国家是 Heaven 或 CHN的才满足条件


7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC_第3张图片
image.png

7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC_第4张图片
image.png
  • 修改 _Layout.cshtml 当用户满足权限时才显示 OrderFrame 按钮
    image.png
  • 修改GalleryController
    OrderFrame 方法添加属性
 [Authorize(Policy = "CanOrderFrame")]
public async Task OrderFrame(){...}

再运行,用不同用户登录尝试
例如,用 Claire 登录时 Debug 输出信息如下

7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC_第5张图片
image.png

点此查看 github commit

三、API 使用 ABAC

  1. 上面使用的 Policy 比较简单,仅仅用到了 user claim。那么,如果需要更复杂的验证机制,比如用户编辑的图片是不是属于他,服务器当前时间是不是晚上等。

例如下面这几种情况


7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC_第6张图片
image.png

这个时候就需要编写复杂的验证 handler 了


7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC_第7张图片
image.png
  1. 新增类 MustOwnImageRequirement
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;

namespace ImageGallery.API.Authorization
{
    public class MustOwnImageRequirement: IAuthorizationRequirement
    {
        public MustOwnImageRequirement()
        {
        }
    }
}

新增类 MustOwnImageHandler

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ImageGallery.API.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;

namespace ImageGallery.API.Authorization
{
    public class MustOwnImageHandler:AuthorizationHandler
    {
        private readonly IGalleryRepository repository;
        public MustOwnImageHandler(IGalleryRepository repo)
        {
            repository = repo;
        }

        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MustOwnImageRequirement requirement)
        {
            var filterContext = context.Resource as AuthorizationFilterContext;
            if (filterContext == null)
            {
                context.Fail();
                return Task.CompletedTask;
            }

            var imageId = filterContext.RouteData.Values["id"].ToString();
            if (!Guid.TryParse(imageId, out Guid imageGuid))
            {
                context.Fail();
                return Task.CompletedTask;
            }

            var ownerId = context.User.Claims.FirstOrDefault(c => c.Type == "sub").Value;
            if (!repository.IsImageOwner(imageGuid, ownerId)
                && context.User.Claims.FirstOrDefault(c => c.Type == "role").Value != "admin")
            {
                context.Fail();
                return Task.CompletedTask;
            }

            context.Succeed(requirement);
            return Task.CompletedTask;
        }
    }
}

Startup::ConfigureServices()添加如下代码:

            services.AddAuthorization(options =>
            {
                options.AddPolicy(
                    "MustOwnImage",
                    policyBuilder =>
                    {
                        policyBuilder.RequireAuthenticatedUser();
                        policyBuilder.AddRequirements(new MustOwnImageRequirement());
                    });
            });
            services.AddScoped();

ImageController在相关接口添加属性

[Authorize("MustOwnImage")]

如果想要在 API 获取额外的 claims,可按照如下修改 GetApiResources

7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC_第8张图片
image.png

运行即可检验代码生效


7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC_第9张图片
image.png

点此查看 github commit

你可能感兴趣的:(7-OAuth2 & OpenID Connect & Asp net core API 使用ABAC)