WCF REST 4.0 用户认证与授权实现

在构建基于WCF REST 4.0的服务时,实现用户认证和授权是一个常见的需求。本文将介绍如何在WCF REST服务中实现基于服务类型的用户认证和基于角色的授权。

在WCF服务中,有多种方式可以进行用户认证和授权。本文示例中,用户认证的Cookie将由登录页面创建,并用于后续对REST服务的请求进行授权。

使用代码

通常,使用Principal Permission属性来授权用户特定角色。例如:

[WebGet(UriTemplate = "")] [PrincipalPermission(SecurityAction.Demand, Role = "Admin")] public List<SampleItem> GetCollection(){}

但是,即使用户使用Membership提供者进行认证,并且HTTPContext.Current.User.Identity在服务级别可用,Principal Permission属性仍然会抛出安全异常。这是因为Principal Permission属性检查的是System.Threading.Thread.CurrentPrincipal.Identity,而不是HTTPContext.Identity。

解决方案

为了解决这个问题,需要为WCF服务创建自定义Principal和授权策略。然后,将使用ServiceBehaviour将此策略与WCF REST服务挂钩。

以下是自定义Principal的代码:

public class CustomPrincipal : IPrincipal { private IIdentity _identity; public IIdentity Identity { get { return _identity; } } public CustomPrincipal(IIdentity identity) { _identity = identity; } public bool IsInRole(string role) { return Roles.IsUserInRole(role); } }

在这里,使用了ASP.NET Membership Role提供者来验证用户是否在特定角色中。也可以实现不使用Membership提供者的自定义实现。

现在创建一个授权策略,将自定义Principal设置到评估上下文中:

public class AuthorizationPolicy : IAuthorizationPolicy { string id = Guid.NewGuid().ToString(); public string Id { get { return this.id; } } public System.IdentityModel.Claims.ClaimSet Issuer { get { return System.IdentityModel.Claims.ClaimSet.System; } } public bool Evaluate(EvaluationContext evaluationContext, ref object state) { IIdentity client = HttpContext.Current.User.Identity; evaluationContext.Properties["Principal"] = new CustomPrincipal(client); return true; } }

仔细查看,自定义Principal是使用HTTPContext.Identity创建的,该Identity是在用户使用Membership提供者进行认证并设置认证Cookie后创建的。

这可以通过在web.config文件中创建服务行为来完成。但是在这里,通过实现IServiceBehavior并附加授权策略来创建自定义服务行为。

[AttributeUsage(AttributeTargets.Class)] public class SecurityBehaviorAttribute : Attribute, IServiceBehavior { public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) { List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(); policies.Add(new AuthorizationPolicy()); serviceHostBase.Authorization.ExternalAuthorizationPolicies = policies.AsReadOnly(); ServiceAuthorizationBehavior bh = serviceDescription.Behaviors.Find<ServiceAuthorizationBehavior>(); if (bh != null) { bh.PrincipalPermissionMode = PrincipalPermissionMode.Custom; } else { throw new NotSupportedException(); } } public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { } public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) { } }

在这里,ServiceAuthorizationBehavior PrincipalPermissionMode被设置为Custom,并且授权策略被添加到servicehost。

确保将服务行为作为属性添加到服务类。

[ServiceContract] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] [SecurityBehavior] public class Service1 { [WebGet(UriTemplate = "")] [PrincipalPermission(SecurityAction.Demand, Role = "Admin")] public List<SampleItem> GetCollection() { var value = System.Web.HttpContext.Current.User.Identity.IsAuthenticated; return new List<SampleItem>() { new SampleItem() { Id = 1, StringValue = "Hello" } }; } }

现在可以将PrincipalPermission属性添加到任何Web方法中,并授权用户特定角色。还可以实施自定义PrincipalPermission属性来控制授权的粒度。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485