大家都知道,微软企业库中的Security Application Block是把权限规则写在配置文件中的(app.config,web.config),并没有提供存在数据库的实现形式。我去年就向企业库项目组的人建议在SAB中加入这一实现形式,遗憾的是,直到现在的3.1版本,还是没有实现这一功能。
还好GotDotNet上有人提供了这一功能的扩展:Database Rules Provider ,不过这个扩展没有权限操作的功能(添加,删除,修改权限。。。),不方便大家的日常使用,所以我就对其作了一些修改,加入了权限操作功能。现在放出来与大家共享:)
项目下载:Database Authorization Provider.rar
DbRulesManager.cs:
1
using System;
2
using System.Data;
3
using System.Data.Common;
4
using System.Data.SqlClient;
5
using System.Configuration;
6
using System.Collections.Generic;
7
using System.Security.Principal;
8
using System.Web.Security;
9
10
using Microsoft.Practices.ObjectBuilder;
11
using Microsoft.Practices.EnterpriseLibrary.Security;
12
//using Microsoft.Practices.EnterpriseLibrary.Security.Authorization;
13
using Microsoft.Practices.EnterpriseLibrary.Security.Configuration;
14
using Microsoft.Practices.EnterpriseLibrary.Data;
15
using Microsoft.Practices.EnterpriseLibrary.Configuration;
16
using System.Configuration.Provider;
17
18
namespace Kreeg.EnterpriseLibrary.Security.Database.Authorization
19

{
20
/**//// <summary>
21
/// Class for retrieving rules from the database
22
/// </summary>
23
public class DbRulesManager
24
{
25
26
private Microsoft.Practices.EnterpriseLibrary.Data.Database dbRules = null;
27
/**//// <summary>
28
/// Creates a Database Rules Manager instance
29
/// </summary>
30
/// <param name="databaseService">The Database Instance to use to query the data(要查询数据的数据库实例)</param>
31
/// <param name="config">The configuration context</param>
32
public DbRulesManager(string databaseService)
33
{
34
//DatabaseProviderFactory factory = new DatabaseProviderFactory(config);
35
dbRules = DatabaseFactory.CreateDatabase(databaseService);
36
}
37
38
39
/**//// <summary>
40
/// Retrieves a rule from the database
41
/// </summary>
42
/// <param name="Name">The name of the rule</param>
43
/// <returns>An AuthorizationRuleData object</returns>
44
public AuthorizationRuleData GetRule(string name)
45
{
46
47
AuthorizationRuleData rule = null;
48
49
DbCommand cmd = dbRules.GetStoredProcCommand("dbo.GetRuleByName");
50
dbRules.AddInParameter(cmd, "Name", DbType.String, name);
51
52
using(IDataReader reader = dbRules.ExecuteReader(cmd))
53
{
54
if(reader.Read())
55
{
56
rule = GetRuleFromReader(reader);
57
}
58
}
59
60
return rule;
61
}
62
63
private AuthorizationRuleData GetRuleFromReader(IDataReader reader)
64
{
65
AuthorizationRuleData rule = new AuthorizationRuleData();
66
rule.Name = reader.GetString(reader.GetOrdinal("Name"));
67
rule.Expression = reader.GetString(reader.GetOrdinal("Expression"));
68
69
return rule;
70
}
71
72
73
/**////// <summary>
74
///// Retrieves all rules in the database as a DataSet
75
///// </summary>
76
///// <returns>A DataSet containing all of the rules</returns>
77
//public DataSet GetAllRules()
78
//{
79
// DbCommand cmd = dbRules.GetStoredProcCommand("dbo.GetAllRules");
80
81
// using(DataSet ds = dbRules.ExecuteDataSet(cmd))
82
// {
83
// return ds;
84
// }
85
//}
86
87
88
/**//// <summary>
89
/// Retrieves all rules in the database as a Collection
90
/// </summary>
91
/// <returns>An AuthorizationRuleDataCollection containing all of the rules</returns>
92
public List<AuthorizationRuleData> GetAllRulesAsCollection()
93
{
94
List<AuthorizationRuleData> rules = new List<AuthorizationRuleData>();
95
96
DbCommand cmd = dbRules.GetStoredProcCommand("dbo.GetAllRules");
97
98
using(IDataReader reader = dbRules.ExecuteReader(cmd))
99
{
100
while(reader.Read())
101
{
102
AuthorizationRuleData rule = GetRuleFromReader(reader);
103
rules.Add(rule);
104
}
105
}
106
return rules;
107
}
108
109
/**//// <summary>
110
/// Inserts a rule into the database
111
/// </summary>
112
/// <param name="name">The name of the rule</param>
113
/// <param name="expression">The expression defining the rule</param>
114
public void InsertRule(string name, string expression,string description)
115
{
116
DbCommand cmd = dbRules.GetStoredProcCommand("dbo.InsertRule");
117
dbRules.AddInParameter(cmd, "Name", DbType.String, name);
118
dbRules.AddInParameter(cmd, "Expression", DbType.String, expression);
119
dbRules.AddInParameter(cmd, "Description",DbType.String, description);
120
121
dbRules.ExecuteNonQuery(cmd);
122
}
123
124
/**//// <summary>
125
/// Saves the rule to the database
126
/// </summary>
127
/// <param name="ruleId">The Rule Id</param>
128
/// <param name="name">The name of the rule</param>
129
/// <param name="expression">The expression</param>
130
public void UpdateRuleById(int ruleId, string name, string expression)
131
{
132
DbCommand cmd = dbRules.GetStoredProcCommand("dbo.UpdateRuleById");
133
dbRules.AddInParameter(cmd, "id", DbType.Int32, ruleId);
134
dbRules.AddInParameter(cmd, "Name", DbType.String, name);
135
dbRules.AddInParameter(cmd, "Expression", DbType.String, expression);
136
//dbRules.AddInParameter(cmd, "Description", DbType.String, description);
137
138
dbRules.ExecuteNonQuery(cmd);
139
}
140
141
/**//// <summary>
142
/// Removes a rule from the database
143
/// </summary>
144
/// <param name="ruleId">The ruleid to remove</param>
145
public void DeleteRuleById(int ruleId)
146
{
147
DbCommand cmd = dbRules.GetStoredProcCommand("dbo.DeleteRuleById");
148
dbRules.AddInParameter(cmd, "id", DbType.Int32, ruleId);
149
150
dbRules.ExecuteNonQuery(cmd);
151
}
152
153
154
/**//***************** Follow Function Created by levinknight 2006.06.07 *****************/
155
156
GetAllRules#region GetAllRules
157
public string[] GetAllRules()
158
{
159
string rules = string.Empty;
160
DbCommand cmd = dbRules.GetStoredProcCommand("dbo.GetAllRules");
161
162
using (DataSet ds = dbRules.ExecuteDataSet(cmd))
163
{
164
foreach (DataRow rule in ds.Tables[0].Rows)
165
{
166
rules += (string)rule["Name"] + ",";
167
}
168
169
if (rules.Length >0)
170
{
171
rules = rules.Substring(0,rules.Length -1);
172
return rules.Split(',');
173
}
174
175
return new string[0];
176
}
177
}
178
#endregion
179
180
GetRulesForUser by IPrincipal#region GetRulesForUser by IPrincipal
181
public string[] GetRulesForUser(IPrincipal principal)
182
{
183
if (principal == null)
184
{
185
throw new ArgumentException("Principal cannot be null.");
186
}
187
188
return GetEffectiveRules(principal);
189
}
190
#endregion
191
192
GetRulesForuser by Username#region GetRulesForuser by Username
193
public string[] GetRulesForUser(string username)
194
{
195
string[] roles = Roles.GetRolesForUser(username);
196
IPrincipal principal = new GenericPrincipal(new GenericIdentity(username),roles);
197
198
return GetEffectiveRules(principal);
199
}
200
#endregion
201
202
GetRulesForRole by Role'Name#region GetRulesForRole by Role'Name
203
public string[] GetRulesForRole(string rolename)
204
{
205
string[] roles = new string[1]
{rolename};
206
IPrincipal principal = new GenericPrincipal(new GenericIdentity(""), roles);
207
208
return GetEffectiveRules(principal);
209
}
210
#endregion
211
212
GetEffectiveRules Service for GetRulesFor User or Role#region GetEffectiveRules Service for GetRulesFor User or Role
213
private string[] GetEffectiveRules(System.Security.Principal.IPrincipal principal)
214
{
215
string rules = "";
216
List<AuthorizationRuleData> ruleCollection = GetAllRulesAsCollection();
217
218
try
219
{
220
foreach (AuthorizationRuleData rule in ruleCollection)
221
{
222
if ( IsInRule(principal,rule.Expression) )
223
{
224
rules += rule.Name + ",";
225
}
226
}
227
}
228
catch (SyntaxException)
229
{
230
throw new ProviderException("返回有效权限时发生了错误,权限表达式非法");
231
}
232
233
if (rules.Length > 0)
234
{
235
//删除最末尾的逗号
236
rules = rules.Substring(0,rules.Length - 1);
237
return rules.Split(',');
238
}
239
240
return new string[0];
241
}
242
#endregion
243
244
AddUserToRule#region AddUserToRule
245
246
public void AddUserToRule(string ruleName,string username)
247
{
248
if (ruleName.Length == 0 || username.Length == 0)
249
{
250
throw new ProviderException("权限名和用户名都不能为空");
251
}
252
253
string[] roles = Roles.GetRolesForUser(username);
254
IPrincipal principal = new GenericPrincipal(new GenericIdentity(username), roles);
255
256
AuthorizationRuleData rule = GetRule(ruleName);
257
258
if (rule == null)
259
{
260
throw new ProviderException(string.Format("权限: '{0}'不在数据库中",ruleName));
261
}
262
263
264
if ( IsInRule(principal,rule.Expression) )
265
{
266
throw new ProviderException(string.Format("用户: '{0}'已经拥有权限: '{1}'",username,ruleName));
267
}
268
269
string ruleExpression = string.Empty;
270
string tempExpression = string.Empty;
271
272
if (rule.Expression.Contains(string.Format(" AND (NOT I:{0})", username)))
273
{
274
tempExpression = ruleExpression = rule.Expression.Replace(string.Format(" AND (NOT I:{0})", username), "");
275
if (IsInRule(principal, tempExpression))
276
{
277
ruleExpression = rule.Expression.Replace(string.Format(" AND (NOT I:{0})", username), "");
278
}
279
else
280
{
281
ruleExpression = rule.Expression.Replace(string.Format(" AND (NOT I:{0})", username),
282
string.Format(" OR (I:{0})", username)
283
);
284
}
285
}
286
else if (rule.Expression.Contains(string.Format("(NOT I:{0})", username)))
287
{
288
ruleExpression = rule.Expression.Replace(string.Format("(NOT I:{0})", username),
289
string.Format("(I:{0})", username)
290
);
291
}
292
else
293
{
294
ruleExpression = rule.Expression + string.Format(" OR (I:{0})", username);
295
}
296
297
try
298
{
299
new Parser().Parse(ruleExpression);
300
}
301
catch (SyntaxException)
302
{
303
throw;
304
}
305
306
UpdateRuleByName(rule.Name,ruleExpression);
307
}
308
309
#endregion
310
311
RemoveUserFromRule#region RemoveUserFromRule
312
public void RemoveUserFromRule(string ruleName, string username)
313
{
314
if (ruleName.Length == 0 || username.Length == 0)
315
{
316
throw new ProviderException("权限名和用户名都不能为空");
317
}
318
319
string[] roles = Roles.GetRolesForUser(username);
320
IPrincipal principal = new GenericPrincipal(new GenericIdentity(username), roles);
321
322
Parser parser = new Parser();
323
AuthorizationRuleData rule = GetRule(ruleName);
324
325
if ( !parser.Parse(rule.Expression).Evaluate(principal) )
326
{
327
throw new ProviderException(string.Format("用户: '{0}'已经没有权限: '{1}'", username,ruleName));
328
}
329
330
string ruleExpression;
331
332
//此用户已经拥有了此权限
333
if (rule.Expression.Contains(string.Format(" OR (I:{0})", username)))
334
{
335
ruleExpression = rule.Expression.Replace(string.Format(" OR (I:{0})", username), "");
336
}
337
//后面有表达式 OR
338
else if (rule.Expression.Contains(string.Format("(I:{0}) OR ", username)))
339
{
340
ruleExpression = rule.Expression.Replace(string.Format("(I:{0}) OR ", username), "");
341
342
}
343
//后面有表达式 AND
344
else if (rule.Expression.Contains(string.Format("(I:{0}) AND ", username)))
345
{
346
ruleExpression = rule.Expression.Replace(string.Format("(I:{0}) AND ", username), "");
347
}
348
//只有此用户拥有此权限
349
else if (rule.Expression.Contains(string.Format("(I:{0})", username)))
350
{
351
//ruleExpression = rule.Expression.Replace(string.Format("(I:{0})", username), "");
352
throw new ProviderException("权限必须属于至少一个角色或用户!!!");
353
}
354
//只是此用户所属的角色拥有此权限
355
else
356
{
357
ruleExpression = rule.Expression + string.Format(" AND (NOT I:{0})", username);
358
}
359
360
UpdateRuleByName(ruleName,ruleExpression);
361
}
362
#endregion
363
364
AddRoleToRule#region AddRoleToRule
365
public void AddRoleToRule(string ruleName,string roleName)
366
{
367
if (ruleName.Length == 0 || roleName.Length ==0)
368
{
369
throw new ProviderException("权限名和角色名都不能为空");
370
}
371
372
string[] roles = new string[1]
{roleName};
373
IPrincipal principal = new GenericPrincipal( new GenericIdentity(""),roles );
374
375
Parser parser = new Parser();
376
AuthorizationRuleData rule = GetRule(ruleName);
377
BooleanExpression parsedExpression;
378
379
if (rule == null)
380
{
381
throw new ProviderException(string.Format("权限: '{0}'不在数据库中", ruleName));
382
}
383
384
parsedExpression = parser.Parse(rule.Expression);
385
if (parsedExpression.Evaluate(principal))
386
{
387
throw new ProviderException(string.Format("角色: '{0}'已经拥有权限: '{1}'", roleName, ruleName));
388
}
389
390
string ruleExpression = string.Empty;
391
392
if (rule.Expression.Contains(string.Format(" AND (NOT R:{0})", roleName)))
393
{
394
ruleExpression = rule.Expression.Replace(string.Format(" AND (NOT R:{0})", roleName),
395
string.Format(" OR (R:{0})", roleName)
396
);
397
}
398
else
399
{
400
ruleExpression = rule.Expression + string.Format(" OR (R:{0})", roleName);
401
}
402
403
ruleExpression = rule.Expression + string.Format(" OR (R:{0})", roleName);
404
405
try
406
{
407
parser.Parse(ruleExpression);
408
}
409
catch (SyntaxException)//权限表达式非法
410
{
411
throw new ApplicationException("权限表达式非法");
412
}
413
414
UpdateRuleByName(rule.Name, ruleExpression);
415
416
}
417
#endregion
418
419
RemoveRoleFromRule#region RemoveRoleFromRule
420
public void RemoveRoleFromRule(string ruleName,string roleName)
421
{
422
string[] roles;
423
roles = new string[1]
{ roleName };
424
425
if (ruleName.Length == 0 || roleName.Length == 0)
426
{
427
throw new ProviderException("权限名和角色名都不能为空");
428
}
429
430
IPrincipal principal;
431
principal= new GenericPrincipal(new GenericIdentity(""), roles);
432
433
Parser parser = new Parser();
434
AuthorizationRuleData rule = GetRule(ruleName);
435
436
if (!parser.Parse(rule.Expression).Evaluate(principal))
437
{
438
throw new ProviderException(string.Format("角色: '{0}'已经没有权限: '{1}'", roleName, ruleName));
439
}
440
441
string ruleExpression = string.Empty;
442
int i = 0;
443
444
//计算有几个角色拥有此权限
445
foreach (string role in Roles.GetAllRoles())
446
{
447
roles[0] = role;
448
principal = new GenericPrincipal(new GenericIdentity(""),roles);
449
450
if (parser.Parse(rule.Expression).Evaluate(principal))
451
{
452
i++;
453
}
454
}
455
456
if (i < 2)
457
{
458
throw new ProviderException("每个权限至少要属于一个角色!");
459
}
460
461
462
//此角色已经拥有了此权限
463
if (rule.Expression.Contains(string.Format(" OR (R:{0})", roleName)))
464
{
465
ruleExpression = rule.Expression.Replace(string.Format(" OR (R:{0})", roleName), "");
466
}
467
//后面有表达式 OR
468
else if (rule.Expression.Contains(string.Format("(R:{0}) OR ", roleName)))
469
{
470
ruleExpression = rule.Expression.Replace(string.Format("(R:{0}) OR ", roleName), "");
471
472
}
473
//后面有表达式 AND
474
else if (rule.Expression.Contains(string.Format("(R:{0}) AND ", roleName)))
475
{
476
ruleExpression = rule.Expression.Replace(string.Format("(R:{0}) AND ", roleName), "");
477
}
478
//只有此角色拥有此权限
479
//else if (rule.Expression.Contains(string.Format("(R:{0})", roleName)))
480
//{
481
// //ruleExpression = rule.Expression.Replace(string.Format("(I:{0})", username), "");
482
// throw new ProviderException("权限必须属于至少一个角色或用户!!!");
483
//}
484
/**/////只是此角色拥有此权限
485
//else
486
//{
487
// ruleExpression = rule.Expression + string.Format(" AND (NOT I:{0})", roleName);
488
//}
489
490
UpdateRuleByName(ruleName, ruleExpression);
491
}
492
#endregion
493
494
UpdateRuleByName#region UpdateRuleByName
495
private void UpdateRuleByName(string ruleName,string ruleExpression)
496
{
497
DbCommand cmd = dbRules.GetStoredProcCommand("dbo.UpdateRuleByName");
498
dbRules.AddInParameter(cmd, "Name", DbType.String, ruleName);
499
dbRules.AddInParameter(cmd, "Expression", DbType.String, ruleExpression);
500
501
dbRules.ExecuteNonQuery(cmd);
502
}
503
#endregion
504
505
DeleteRuleByName#region DeleteRuleByName
506
public void DeleteRuleByName(string ruleName)
507
{
508
if (ruleName.Length == 0)
509
{
510
throw new ProviderException("要删除的权限名不能为空");
511
}
512
513
DbCommand cmd = dbRules.GetStoredProcCommand("dbo.DeleteRuleByName");
514
dbRules.AddInParameter(cmd, "Name", DbType.String, ruleName);
515
516
dbRules.ExecuteNonQuery(cmd);
517
}
518
#endregion
519
520
CreateRule#region CreateRule
521
public void CreateRule(string ruleName,string description,string[] roles)
522
{
523
string ruleExpression;
524
string roleRules = string.Empty;
525
//string userRules = string.Empty;
526
527
if (ruleName == null)
528
{
529
throw new ArgumentException("权限名不能为空");
530
}
531
532
if (roles.Length == 0)
533
{
534
throw new ProviderException("创建权限时必须指明权限的所属角色");
535
}
536
537
if (roles.Length > 0)
538
{
539
foreach (string role in roles)
540
{
541
roleRules += string.Format("(R:{0}) OR ",role);
542
}
543
544
if (roles.Rank > 0)
545
{
546
roleRules = roleRules.Substring(0, roleRules.Length - 4);
547
}
548
}
549
550
ruleExpression = roleRules;
551
552
try
553
{
554
new Parser().Parse(ruleExpression);
555
}
556
catch (SyntaxErrorException)
557
{
558
throw;
559
}
560
561
InsertRule(ruleName,ruleExpression,description);
562
}
563
#endregion
564
565
IsInRule#region IsInRule
566
private bool IsInRule(IPrincipal principal,string ruleExpression)
567
{
568
Parser parser = new Parser();
569
BooleanExpression parsedExpression;
570
571
try
572
{
573
parsedExpression = parser.Parse(ruleExpression);
574
}
575
catch (SyntaxException)
576
{
577
throw;
578
}
579
580
if (parsedExpression.Evaluate(principal))
581
{
582
return true;
583
}
584
585
return false;
586
}
587
#endregion
588
}
589
}
590