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

前端 未结 1 1608
無奈伤痛
無奈伤痛 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<Evil666Error>(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.

        /// <summary>
    /// Used in ServiceModel's ServiceBehavior for authentication of service operations.
    /// </summary>
    public class IdentityValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            using (var context = new WebPortalDbContext())
            {
                using (var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(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.
                    }
                }
    
            }
    
        }
    }
    
    /// <summary>
    /// Used in ServiceModel's ServiceBehavior for authorization of service operation, according to the role in PrincipalPermissionAttribute
    /// </summary>
    public class RoleAuthorizationManager : ServiceAuthorizationManager
    {
        protected override bool CheckAccessCore(OperationContext operationContext)
        {
            base.CheckAccessCore(operationContext);
            using (var context = new WebPortalDbContext())
            using (var userStore = new UserStore<ApplicationUser>(context))
            {
                using (var userManager = new UserManager<ApplicationUser>(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.

          <serviceBehaviors>
        <behavior name="authBehavior">
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyNamespace.IdentityValidator,MyNamespace.Security" />
          </serviceCredentials>
          <serviceAuthorization principalPermissionMode="Custom" serviceAuthorizationManagerType="Mynamespace.Security.RoleAuthorizationManager,mynamespace.Security"></serviceAuthorization>
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="True" />
        </behavior>
      </serviceBehaviors>
    
    
    
          <service name="Fonlow.Demo.RealWorldService.Service1" behaviorConfiguration="authBehavior">
        <!-- Service Endpoints. A Service may provide multiple endpoints -->
        <!-- Not need to define host. Relative  -->
        <endpoint address="" binding="basicHttpsBinding" contract="Fonlow.Demo.RealWorldService.IService1" bindingConfiguration="httpsBindingConfig">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
      </service>
    
    0 讨论(0)
提交回复
热议问题