How to use ASP.NET Identity Model for WCF service authorization and authentication

前端 未结 1 1607
無奈伤痛
無奈伤痛 2021-01-03 14:06

I am working on a ASP.NET 4.5 Web Application which uses ASP.NET Identity model for authentication and authorization.

This web application also hosts a WCF Service a

1条回答
  •  说谎
    说谎 (楼主)
    2021-01-03 14:46

    You use PrincipalPermissionAttribute to decorate the operation implementation for authorization.

        public class Service1 : IService1 
    {
        public string GetData(int value)
        {
            System.Diagnostics.Debug.WriteLine("GetDataCalled");
            if (value == 666)
                throw new FaultException(new Evil666Error() { Message = "Hey, this is 666." });
    
            return string.Format("You entered: {0}", value);
        }
    
        [PrincipalPermission(SecurityAction.Demand, Role="Admin")]
        [PrincipalPermission(SecurityAction.Demand, Role="Customer")]
        public CompositeType GetDataUsingDataContract(CompositeType composite)
        {
            var userName = ServiceSecurityContext.Current.PrimaryIdentity.Name;
    
    
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
    
            if (composite.BoolValue)
            {
                composite.StringValue += "Suffix";
            }
            return composite;
        }
    }
    

    So the first operation needs only authentication, while the 2nd needs authorization.

    Then you need to write custom authentication and authorization codes.

        /// 
    /// Used in ServiceModel's ServiceBehavior for authentication of service operations.
    /// 
    public class IdentityValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            using (var context = new WebPortalDbContext())
            {
                using (var userManager = new UserManager(new UserStore(context)))
                {
                    var user = userManager.Find(userName, password);
                    if (user == null)
                    {
                        var msg = String.Format("Unknown Username {0} or incorrect password {1}", userName, password);
                        Trace.TraceWarning(msg);
                        throw new FaultException(msg);//the client actually will receive MessageSecurityException. But if I throw MessageSecurityException, the runtime will give FaultException to client without clear message.
                    }
                }
    
            }
    
        }
    }
    
    /// 
    /// Used in ServiceModel's ServiceBehavior for authorization of service operation, according to the role in PrincipalPermissionAttribute
    /// 
    public class RoleAuthorizationManager : ServiceAuthorizationManager
    {
        protected override bool CheckAccessCore(OperationContext operationContext)
        {
            base.CheckAccessCore(operationContext);
            using (var context = new WebPortalDbContext())
            using (var userStore = new UserStore(context))
            {
                using (var userManager = new UserManager(userStore))
                {
                    var identity =operationContext.ServiceSecurityContext.PrimaryIdentity;
                    var user = userManager.FindByName(identity.Name);
                    if (user == null)
                    {
                        var msg = String.Format("Unknown Username {0} .", user.UserName);
                        Trace.TraceWarning(msg);
                        throw new FaultException(msg);
                    }
    
                    //Assign roles to the Principal property for runtime to match with PrincipalPermissionAttributes decorated on the service operation.
                    var roleNames = userManager.GetRoles(user.Id).ToArray();//users without any role assigned should then call operations not decorated by PrincipalPermissionAttributes
                    operationContext.ServiceSecurityContext.AuthorizationContext.Properties["Principal"] = new GenericPrincipal(operationContext.ServiceSecurityContext.PrimaryIdentity, roleNames);
    
                    return true;
                }
            }
    
        }
    
    
    }
    

    In the config you should have these to wire them together.

          
        
          
            
          
          
          
          
        
      
    
    
    
          
        
        
        
          
            
          
        
      
    

    0 讨论(0)
提交回复
热议问题