(四)wcf自定义验证
1.继承ServiceAuthorizationManager
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Reflection;
namespace ITestWcfService
{
/// <summary>
/// wcf校验,校验用户是否拥有指定资源权限
/// </summary>
public class StandardServiceAuthorizationManager : ServiceAuthorizationManager
{
/// <summary>
/// 重写校验
/// </summary>
/// <param name="operationContext"></param>
/// <returns></returns>
protected override bool CheckAccessCore(OperationContext operationContext)
{
CheckPermission(operationContext, Guid.NewGuid());
return base.CheckAccessCore(operationContext);
}
/// <summary>
/// 自定义校验实现
/// </summary>
/// <param name="operationContext"></param>
/// <param name="userId"></param>
private void CheckPermission(OperationContext operationContext, Guid userId)
{
var map = ActionPermissionMapCahce.GetMapBy(operationContext);
string action = operationContext.IncomingMessageHeaders.Action;
var requiredPermissions = map[action];
var requiredResourceGrants = requiredPermissions.Select(requiredPermission =>
{
Type resourceTypeType = requiredPermission.ResourceTypeType;
ResourceType resourceType = ResourceType.ConcreteResourceTypes.Values.FirstOrDefault(value => value.GetType().Equals(resourceTypeType));
if (resourceType == null)
{
throw new ApplicationException(string.Format("No such ResourceType named {0}.", resourceTypeType.Name));
}
return new KeyValuePair<Guid, int>(resourceType.Id, requiredPermission.GrantedOperations);
}).ToList();
if (requiredResourceGrants.Count > 0)
{
//校验数据权限
if (!ResourceType.PrincipalHasPermissions(userId, requiredResourceGrants))
{
throw new ApplicationException("You don't have permissions.");
}
}
}
}
internal class ActionPermissionMapCahce
{
static ConcurrentDictionary<string, ReadOnlyDictionary<string, IEnumerable<RequiredPermissionAttribute>>> cache = new ConcurrentDictionary<string, ReadOnlyDictionary<string, IEnumerable<RequiredPermissionAttribute>>>();
public static bool Contains(string contractKey)
{
return cache.ContainsKey(contractKey);
}
public static void Add(string contractKey, IDictionary<string, IEnumerable<RequiredPermissionAttribute>> actionPermissionsMap)
{
cache.TryAdd(contractKey, new ReadOnlyDictionary<string, IEnumerable<RequiredPermissionAttribute>>(actionPermissionsMap));
}
public static IReadOnlyDictionary<string, IEnumerable<RequiredPermissionAttribute>> GetMap(string contractKey)
{
return cache[contractKey];
}
public static IReadOnlyDictionary<string, IEnumerable<RequiredPermissionAttribute>> GetMapBy(OperationContext operationContext)
{
string contractNamespace = operationContext.EndpointDispatcher.ContractNamespace;
string contractName = operationContext.EndpointDispatcher.ContractName;
string contractKey = contractNamespace + "/" + contractName;
if (!ActionPermissionMapCahce.Contains(contractKey))
{
var map = BuildMapFrom(operationContext);
ActionPermissionMapCahce.Add(contractKey, map);
}
return ActionPermissionMapCahce.GetMap(contractKey);
}
private static IDictionary<string, IEnumerable<RequiredPermissionAttribute>> BuildMapFrom(OperationContext operationContext)
{
string contractNamespace = operationContext.EndpointDispatcher.ContractNamespace;
string contractName = operationContext.EndpointDispatcher.ContractName;
Dictionary<string, IEnumerable<RequiredPermissionAttribute>> actionPermissionsMap = new Dictionary<string, IEnumerable<RequiredPermissionAttribute>>();
ServiceEndpoint endpoint = operationContext.Host.Description.Endpoints.Find(new XmlQualifiedName(contractName, contractNamespace));
ContractDescription contractDescription = endpoint.Contract;
foreach (var operation in contractDescription.Operations)
{
var requiredPermissions = operation.SyncMethod.GetCustomAttributes<RequiredPermissionAttribute>();
var message = operation.Messages.Where(m => m.Direction == MessageDirection.Input).First();
string action = message.Action;
actionPermissionsMap.Add(action, requiredPermissions);
}
return actionPermissionsMap;
}
}
}
2.在wcf服务应用程序新增配置
3.新增校验资源对象
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ITestWcfService
{
/// <summary>
/// 资源对象
/// </summary>
public abstract class ResourceType : IResourceType
{
public abstract Guid Id { get; }
public string Name { get { return this.GetType().Name; } }
public abstract string DisplayName { get; }
public abstract bool HasDataPermisson { get; }
public virtual bool Enabled { get { return true; } }
/// <summary>
/// 所有资源对象
/// </summary>
private static Dictionary<Guid, ResourceType> concreteResourceTypes;
private static readonly object @lock = new object();
/// <summary>
/// 校验是否有该数据权限
/// </summary>
/// <param name="principalId"></param>
/// <param name="resourceGrants"></param>
/// <returns></returns>
public static bool PrincipalHasPermissions(Guid principalId, List<KeyValuePair<Guid, int>> resourceGrants)
{
if (resourceGrants == null)
throw new ArgumentNullException("resourceOperations");
return false;
}
/// <summary>
/// 获取所有资源对象
/// </summary>
public static IReadOnlyDictionary<Guid, ResourceType> ConcreteResourceTypes
{
get
{
if (concreteResourceTypes == null)
{
lock (@lock)
{
if (concreteResourceTypes == null)
{
using (var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()))
using (var container = new CompositionContainer(catalog))
{
var types = container.GetExportedValues<ResourceType>();
concreteResourceTypes = new Dictionary<Guid, ResourceType>();
foreach (var t in types)
{
if (!t.Enabled)
continue;
if (concreteResourceTypes.ContainsKey(t.Id))
{
var existed = concreteResourceTypes[t.Id];
throw new Exception(string.Format("Resource type id duplicated between {0} and {1}.", existed.Name, t.Name));
}
concreteResourceTypes.Add(t.Id, t);
}
}
}
}
}
//NOTE: return a new ReadOnlyDictionary, just in case, to avoid data is modified somewhere and somehow.
return new ReadOnlyDictionary<Guid, ResourceType>(concreteResourceTypes);
}
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ITestWcfService
{
/// <summary>
/// 角色资源对象
/// </summary>
public sealed class RoleResourceType : ResourceType
{
public static readonly Guid TypeId = new Guid("090B4D9B-5677-4595-9394-D5156FD08302");
[Export(typeof(ResourceType))]
public static readonly RoleResourceType Instance = new RoleResourceType();
private RoleResourceType()
{
}
public override Guid Id
{
get { return TypeId; }
}
public override bool HasDataPermisson
{
get { return true; }
}
public override string DisplayName
{
get { return "角色"; }
}
/// <summary>
/// 操作权限
/// </summary>
[Flags]
public enum Operation : int
{
[DisplayText("读取")]
Read = 1,
[DisplayText("新建")]
Create = 2,
[DisplayText("删除")]
Delete = 4,
[DisplayText("更新")]
Update = 8
}
}
}
4.管道新增校验特性
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构