-
Notifications
You must be signed in to change notification settings - Fork 747
/
FunctionAuthCacheBase.cs
200 lines (180 loc) · 8.75 KB
/
FunctionAuthCacheBase.cs
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// -----------------------------------------------------------------------
// <copyright file="FunctionAuthCacheBase.cs" company="OSharp开源团队">
// Copyright (c) 2014-2018 OSharp. All rights reserved.
// </copyright>
// <site>http://www.osharp.org</site>
// <last-editor>郭明锋</last-editor>
// <last-date>2018-05-11 0:59</last-date>
// -----------------------------------------------------------------------
using System.Diagnostics.CodeAnalysis;
namespace OSharp.Authorization;
/// <summary>
/// 功能权限配置缓存基类
/// </summary>
public abstract class FunctionAuthCacheBase<TModuleFunction, TModuleRole, TModuleUser, TFunction, TModule, TModuleKey,
TRole, TRoleKey, TUser, TUserKey>
: IFunctionAuthCache
where TFunction : class, IFunction
where TModule : ModuleBase<TModuleKey>
where TModuleFunction : ModuleFunctionBase<TModuleKey>
where TModuleKey : struct, IEquatable<TModuleKey>
where TModuleRole : ModuleRoleBase<TModuleKey, TRoleKey>
where TModuleUser : ModuleUserBase<TModuleKey, TUserKey>
where TRole : RoleBase<TRoleKey>
where TRoleKey : IEquatable<TRoleKey>
where TUser : UserBase<TUserKey>
where TUserKey : IEquatable<TUserKey>
{
private readonly Random _random = new Random();
private readonly IServiceProvider _serviceProvider;
private readonly IDistributedCache _cache;
private readonly ILogger _logger;
/// <summary>
/// 初始化一个<see cref="FunctionAuthCacheBase{TModuleFunction, TModuleRole, TModuleUser, TFunction, TModule, TModuleKey,TRole, TRoleKey, TUser, TUserKey}"/>类型的新实例
/// </summary>
protected FunctionAuthCacheBase(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_cache = serviceProvider.GetService<IDistributedCache>();
_logger = serviceProvider.GetLogger(GetType());
}
/// <summary>
/// 创建功能权限缓存,只创建 功能-角色集合 的映射,用户-功能 的映射,遇到才即时创建并缓存
/// </summary>
public virtual void BuildRoleCaches()
{
//只创建 功能-角色集合 的映射,用户-功能 的映射,遇到才即时创建并缓存
_serviceProvider.ExecuteScopedWork(provider =>
{
IRepository<TFunction, Guid> functionRepository = provider.GetRequiredService<IRepository<TFunction, Guid>>();
Guid[] functionIds = functionRepository.QueryAsNoTracking(null, false).Select(m => m.Id).ToArray();
foreach (Guid functionId in functionIds)
{
GetFunctionRoles(functionId, provider, true);
}
_logger.LogInformation($"功能权限:创建 {functionIds.Length} 个功能的“Function-Roles[]”缓存");
});
}
/// <summary>
/// 移除指定功能的缓存
/// </summary>
/// <param name="functionIds">功能编号集合</param>
public virtual void RemoveFunctionCaches(params Guid[] functionIds)
{
foreach (Guid functionId in functionIds)
{
string key = GetFunctionRolesKey(functionId);
_cache.Remove(key);
_logger.LogDebug($"移除功能“{functionId}”的“Function-Roles[]”缓存");
}
_logger.LogInformation($"功能权限:移除{functionIds.Length}个“Function-Roles[]”缓存");
}
/// <summary>
/// 移除指定用户的缓存
/// </summary>
/// <param name="userNames">用户编号集合</param>
public virtual void RemoveUserCaches(params string[] userNames)
{
foreach (string userName in userNames)
{
string key = GetUserFunctionsKey(userName);
_cache.Remove(key);
}
}
/// <summary>
/// 获取能执行指定功能的所有角色
/// </summary>
/// <param name="functionId">功能编号</param>
/// <param name="scopeProvider">局部服务提供者</param>
/// <param name="forceRefresh">是否强制刷新</param>
/// <returns>能执行功能的角色名称集合</returns>
public string[] GetFunctionRoles(Guid functionId, IServiceProvider scopeProvider = null, bool forceRefresh = false)
{
string key = GetFunctionRolesKey(functionId);
IFunctionHandler functionHandler = _serviceProvider.GetRequiredService<IFunctionHandler>();
var function = functionHandler.GetFunction(functionId);
string[] roleNames;
if (!forceRefresh)
{
roleNames = _cache.Get<string[]>(key);
if (roleNames != null)
{
_logger.LogDebug($"从缓存中获取到功能“{function.Name}”的“Function-Roles[]”缓存,角色数:{roleNames.Length}");
return roleNames;
}
}
IServiceProvider provider = scopeProvider;
IServiceScope serviceScope = null;
if (provider == null)
{
serviceScope = _serviceProvider.CreateScope();
provider = serviceScope.ServiceProvider;
}
IRepository<TModuleFunction, Guid> moduleFunctionRepository = provider.GetRequiredService<IRepository<TModuleFunction, Guid>>();
TModuleKey[] moduleIds = moduleFunctionRepository.QueryAsNoTracking(m => m.FunctionId.Equals(functionId)).Select(m => m.ModuleId).Distinct()
.ToArray();
if (moduleIds.Length == 0)
{
serviceScope?.Dispose();
return Array.Empty<string>();
}
roleNames = Array.Empty<string>();
IRepository<TModuleRole, Guid> moduleRoleRepository = provider.GetRequiredService<IRepository<TModuleRole, Guid>>();
TRoleKey[] roleIds = moduleRoleRepository.QueryAsNoTracking(m => moduleIds.Contains(m.ModuleId)).Select(m => m.RoleId).Distinct().ToArray();
if (roleIds.Length > 0)
{
IRepository<TRole, TRoleKey> roleRepository = provider.GetRequiredService<IRepository<TRole, TRoleKey>>();
roleNames = roleRepository.QueryAsNoTracking(m => roleIds.Contains(m.Id)).Select(m => m.Name).Distinct().ToArray();
}
// 有效期为 7 ± 1 天
int seconds = 7 * 24 * 3600 + _random.Next(-24 * 3600, 24 * 3600);
_cache.Set(key, roleNames, seconds);
_logger.LogDebug($"添加功能“{function.Name}”的“Function-Roles[]”缓存,角色数:{roleNames.Length}");
serviceScope?.Dispose();
return roleNames;
}
/// <summary>
/// 获取指定用户的所有特权功能
/// </summary>
/// <param name="userName">用户名</param>
/// <returns>用户的所有特权功能</returns>
public virtual Guid[] GetUserFunctions(string userName)
{
string key = GetUserFunctionsKey(userName);
Guid[] functionIds = _cache.Get<Guid[]>(key);
if (functionIds != null)
{
_logger.LogDebug($"从缓存中获取到用户“{userName}”的“User-Function[]”缓存");
return functionIds;
}
functionIds = _serviceProvider.ExecuteScopedWork(provider =>
{
IRepository<TUser, TUserKey> userRepository = provider.GetRequiredService<IRepository<TUser, TUserKey>>();
TUserKey userId = userRepository.QueryAsNoTracking(m => m.UserName == userName).Select(m => m.Id).FirstOrDefault();
if (Equals(userId, default(TUserKey)))
{
return Array.Empty<Guid>();
}
IRepository<TModuleUser, Guid> moduleUserRepository = provider.GetRequiredService<IRepository<TModuleUser, Guid>>();
TModuleKey[] moduleIds = moduleUserRepository.QueryAsNoTracking(m => m.UserId.Equals(userId)).Select(m => m.ModuleId).Distinct().ToArray();
IRepository<TModule, TModuleKey> moduleRepository = provider.GetRequiredService<IRepository<TModule, TModuleKey>>();
moduleIds = moduleIds.Select(m => moduleRepository.QueryAsNoTracking(n => n.TreePathString.Contains("$" + m + "$"))
.Select(n => n.Id)).SelectMany(m => m).Distinct().ToArray();
IRepository<TModuleFunction, Guid> moduleFunctionRepository = provider.GetRequiredService<IRepository<TModuleFunction, Guid>>();
return moduleFunctionRepository.QueryAsNoTracking(m => moduleIds.Contains(m.ModuleId)).Select(m => m.FunctionId).Distinct().ToArray();
});
// 有效期为 7 ± 1 天
int seconds = 7 * 24 * 3600 + _random.Next(-24 * 3600, 24 * 3600);
_cache.Set(key, functionIds, seconds);
_logger.LogDebug($"创建用户“{userName}”的“User-Function[]”缓存");
return functionIds;
}
private static string GetFunctionRolesKey(Guid functionId)
{
return $"Auth:Function:FunctionRoles:{functionId}";
}
private static string GetUserFunctionsKey(string userName)
{
return $"Auth:Function:UserFunctions:{userName}";
}
}