1、自定义鉴权

参考文档:https://learn.microsoft.com/zh-cn/aspnet/core/security/authorization/iard?view=aspnetcore-10.0

我的想法是通过自定义特性来实现对接口鉴权,所以需要先定义一个特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using Microsoft.AspNetCore.Authorization;

namespace WebApi.Attributes {
public class PermissionAuthorizeAttribute : AuthorizeAttribute,
IAuthorizationRequirement, IAuthorizationRequirementData {
public string PermissionCode { get; set; }
public PermissionAuthorizeAttribute(string permissionCode) {
PermissionCode = permissionCode;
}
public IEnumerable<IAuthorizationRequirement> GetRequirements() {
yield return this;
}
}
}

定义特性后,要创建自己的鉴权处理器,通过覆写 HandleRequirementAsync 来鉴权,如果没有 context.Succeed()就会返回 403 状态码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Model.Database;
using System.Security.Claims;
using WebApi.Attributes;

namespace WebApi.Handler {
public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionAuthorizeAttribute> {
private readonly IServiceScopeFactory _scopeFactory;
public PermissionAuthorizationHandler(
IServiceScopeFactory scopeFactory
) {
_scopeFactory = scopeFactory;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizeAttribute requirement) {
var roleClaims = context.User.FindAll(ClaimTypes.Role).ToList();
if (!roleClaims.Any()) {
return;
}
var roleNames = roleClaims.Select(c=>c.Value).ToList();
// 判断是否有SuperAdmin角色
if (roleNames.Contains("SuperAdmin")) {
context.Succeed(requirement);
return;
}
using var scope = _scopeFactory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<EdgeDbContext>();
string requiredPermission = requirement.PermissionCode;
// 判断是否有指定权限
bool hasPermission = await db.Roles.Where(r => roleNames.Contains(r.RoleName)).Join(
db.RolePermissions,
r => r.RoleId,
rp => rp.RoleId,
(r, rp) => rp.PermissionId)
.Join(
db.Permissions,
rpId => rpId,
p => p.PermissionId,
(rpId, p) => p.Code)
.AnyAsync(code => code == requiredPermission);

if (hasPermission) {
context.Succeed(requirement);
}
}
}
}

最后就是注册自定义鉴权处理器

1
2
3
// 自定义认证处理器
builder.Services.AddSingleton<IAuthorizationHandler,
PermissionAuthorizationHandler>();

使用方法如下

1
2
3
4
5
6
7
8
9
10
[HttpGet("OpenDoor")]
[PermissionAuthorize("DeviceType:AccessControl:Control")]
public string OpenDoor() {
return "用户具有门禁控制器控制权限,允许开门";
}
[HttpGet("AddUser")]
[PermissionAuthorize("Action:User:Add")]
public string AddUser() {
return "用户具有添加用户权限,已添加用户";
}