ASP.NET Core : 二十七. JWT与用户授权(细化到Action)(二)

简介: 上一章分享了如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新,本章继续进行下一步,用户授权。涉及到的例子也以上一章的为基础。

三、基于声明授权

对于上例来说,本质上也是基于声明(Claim)的授权,因为张三的"TestPutBookRole"角色也是作为一个Claim添加到证书中的。只不过采用了特定的ClaimTypes.Role。那么是否可以将其他的普通Claim作为授权的依据呢?当然是可以的。


这里涉及到了另一个单词“Policy”,翻译为策略?也就是说,可以把一系列的规则(例如要求姓名为李四,账号为002,国籍为中国等等)组合在一起,形成一个Policy,只有满足这个Policy的才可以被授权访问。


下面我们就新建一个Policy,在Startup的ConfigureServices中添加授权代码:

services.AddAuthorization(options=>options.AddPolicy("Name",policy=> {
   policy.RequireClaim(ClaimTypes.Name, "张三");
   policy.RequireClaim(ClaimTypes.NameIdentifier,"001");
}));

在BookController中添加一个Action如下

[HttpDelete]
[Authorize(Policy = "TestPolicy")]
public JsonResult Delete()
{
    return new JsonResult("Delete Book ...");
}

可以通过张三和李四的账号测试一下,只有使用张三的账号获取的Token能访问成功。

四、基于策略自定义授权

上面介绍了两种授权方式,现在有个疑问,通过角色授权,只适合一些小型项目,将几个功能通过角色区分开就可以了。


通过声明的方式,目测实际项目中需要在Startup中先声明一系列的Policy,然后在Controller或Action中使用。


这两种方式都感觉不好。例如经常存在这样的需求:一个用户可以有多个角色,每个角色对应多个可访问的API地址(将授权细化到具体的Action)。用户还可以被特殊的授予某个API地址的权限。


这样的需求采用上面的两种方式实现起来都很麻烦,好在ASP.NET Core提供了方便的扩展方式。

1.样例数据

将上面的需求汇总一下,最终可以形成如下形式的数据:

/// <summary>
/// 虚拟数据,模拟从数据库或缓存中读取用户相关的权限
/// </summary>
public static class TemporaryData
{
    public readonly static List<UserPermissions> UserPermissions = new List<UserPermissions> {
        new UserPermissions {
            Code = "001",
            Permissions = new List<Permission> {
                new Permission { Code = "A1", Name = "student.create", Url = "/api/student",Method="post" },
                new Permission { Code = "A2", Name = "student.delete", Url = "/api/student",Method="delete"}
            }
        },
        new UserPermissions {
            Code = "002",
            Permissions = new List<Permission> {
                new Permission { Code = "B1", Name = "book.create", Url = "/api/book" ,Method="post"},
                new Permission { Code = "B2", Name = "book.delete", Url = "/api/book" ,Method="delete"}
            }
        },
    };
    public static UserPermissions GetUserPermission(string code)
    {
        return UserPermissions.FirstOrDefault(m => m.Code.Equals(code));
    }
}

涉及到的两个类如下:

    public class Permission
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public string Url { get; set; }
        public string Method { get; set; }
    }
    public class UserPermissions
    {
        public string Code { get; set; }
        public List<Permission> Permissions { get; set; }
    }

2.自定义处理程序

下面就是根据样例数据来制定相应的处理程序了。这涉及到IAuthorizationRequirement和AuthorizationHandler两个内容。


IAuthorizationRequirement是一个空的接口,主要用于提供授权所需要满足的“要求”,或者说是“规则”。AuthorizationHandler则是对请求和“要求”的联合处理。


新建一个PermissionRequirement实现IAuthorizationRequirement接口。

public class PermissionRequirement: IAuthorizationRequirement
{
    public List<UserPermissions> UsePermissionList { get { return TemporaryData.UserPermissions; } }
}

很简单的内容。它的“要求”也就是用户的权限列表了,用户的权限列表中包含当前访问的API,则授权通过,否则不通过。

判断逻辑放在新建的PermissionHandler中:

public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
    {
        var code = context.User.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.NameIdentifier));
        if (null != code)
        {
            UserPermissions userPermissions = requirement.UsePermissionList.FirstOrDefault(m => m.Code.Equals(code.Value.ToString()));
            var Request = (context.Resource as AuthorizationFilterContext).HttpContext.Request;
            if (null != userPermissions && userPermissions.Permissions.Any(m => m.Url.ToLower().Equals(Request.Path.Value.ToLower()) && m.Method.ToLower().Equals(Request.Method.ToLower()) ))
            {
                context.Succeed(requirement);
            }
            else
            {
                context.Fail();
            }
        }
        else
        {
            context.Fail();
        }
        return Task.CompletedTask;
    }
}

逻辑很简单不再描述。

3.使用自定义的处理程序

在Startup的ConfigureServices中添加授权代码

services.AddAuthorization(options => options.AddPolicy("Permission", policy => policy.Requirements.Add(new PermissionRequirement())));
services.AddSingleton<IAuthorizationHandler, PermissionHandler>();

将BookController的Delete Action修改一下:

[HttpDelete]
//[Authorize(Policy = "TestPolicy")]
[Authorize(Policy = "Permission")]
public JsonResult Delete()
{
    return new JsonResult("Delete Book ...");
}

测试一下只有李四可以访问这个Action。

目录
相关文章
|
9月前
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
200 5
|
10月前
|
开发框架 .NET C#
在 ASP.NET Core 中创建 gRPC 客户端和服务器
本文介绍了如何使用 gRPC 框架搭建一个简单的“Hello World”示例。首先创建了一个名为 GrpcDemo 的解决方案,其中包含一个 gRPC 服务端项目 GrpcServer 和一个客户端项目 GrpcClient。服务端通过定义 `greeter.proto` 文件中的服务和消息类型,实现了一个简单的问候服务 `GreeterService`。客户端则通过 gRPC 客户端库连接到服务端并调用其 `SayHello` 方法,展示了 gRPC 在 C# 中的基本使用方法。
166 5
在 ASP.NET Core 中创建 gRPC 客户端和服务器
|
9月前
|
开发框架 算法 中间件
ASP.NET Core 中的速率限制中间件
在ASP.NET Core中,速率限制中间件用于控制客户端请求速率,防止服务器过载并提高安全性。通过`AddRateLimiter`注册服务,并配置不同策略如固定窗口、滑动窗口、令牌桶和并发限制。这些策略可在全局、控制器或动作级别应用,支持自定义响应处理。使用中间件`UseRateLimiter`启用限流功能,并可通过属性禁用特定控制器或动作的限流。这有助于有效保护API免受滥用和过载。 欢迎关注我的公众号:Net分享 (239字符)
167 1
|
9月前
|
开发框架 缓存 .NET
GraphQL 与 ASP.NET Core 集成:从入门到精通
本文详细介绍了如何在ASP.NET Core中集成GraphQL,包括安装必要的NuGet包、创建GraphQL Schema、配置GraphQL服务等步骤。同时,文章还探讨了常见问题及其解决方法,如处理复杂查询、错误处理、性能优化和实现认证授权等,旨在帮助开发者构建灵活且高效的API。
208 3
|
9月前
|
JSON 安全 Java
什么是JWT?如何使用Spring Boot Security实现它?
什么是JWT?如何使用Spring Boot Security实现它?
1612 5
|
SQL Java 测试技术
在Spring boot中 使用JWT和过滤器实现登录认证
在Spring boot中 使用JWT和过滤器实现登录认证
620 0
|
11月前
|
JSON 安全 算法
|
8月前
|
XML JavaScript Java
SpringBoot集成Shiro权限+Jwt认证
本文主要描述如何快速基于SpringBoot 2.5.X版本集成Shiro+JWT框架,让大家快速实现无状态登陆和接口权限认证主体框架,具体业务细节未实现,大家按照实际项目补充。
480 11
|
11月前
|
存储 安全 Java
|
JSON 安全 Java
使用Spring Boot和JWT实现用户认证
使用Spring Boot和JWT实现用户认证