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

£可爱£侵袭症+ 提交于 2019-12-30 05:24:05

问题


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 and at the same time consumes it. There is another WPF-based application which will use this hosted WCF Service hosted (along with web application as a client itself).

I want to authorize and authenticate each WCF Service request (coming either from Web Application Client or WPF Client).

In ideal scenario, I would like to use same ASP.NET Identity Model for authentication/authorization of WCF operation contracts. How can I achieve this from Web Application as well as WPF application?


回答1:


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>


来源:https://stackoverflow.com/questions/24910304/how-to-use-asp-net-identity-model-for-wcf-service-authorization-and-authenticati

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!