繁体   English   中英

如何对自托管WCF OData服务使用身份验证

[英]How to use authentication with self hosted WCF OData service

我有一个WCF DataService,它与DataServiceHost一起在控制台应用程序中运行

我可以成功启动主机,并使用以下代码查询WCF DataService

public void Start()
{
    var uri = new Uri("http://localhost:12345/Products");
    var host = new DataServideHost(typeof(ProductsDataService), uri);
    if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
        host.Description.Behaviors.Add(new ServiceMetadataBehavior());
    if (host.Description.Behaviors.Find<ServiceDebugBehavior>() == null)
        host.Description.Behaviors.Add(new ServiceDebugBehavior());
    host.Description.Behaviors.Find<ServiceMetadataBehavior()
        .HttpGetEnabled = true;
    host.Description.Behaviors.Find<ServiceDebugBehavior>()
        .IncludeExceptionDetailInFaults = true;

    host.AddServiceEndpoint(
        new ServiceEndpoint(ContractDescription.GetContract(serviceType))
        {
            Name = "default",
            Address = new EndpointAddress(baseAddress),
            Contract = ContractDescription.GetContract(
                typeof(IRequestHandler)),
            Binding = new WebHttpBinding(),
        });

    host.Open();
}

我如何通过基本身份验证或其他方式保护此服务的安全(请注意,我的服务将通过https保护)

我找到了很多有关如何使用IHttpModule使用IIS保护DataService的示例,但是我还发现有帖子说我不能在我的DataServiceHost中使用HttpModules。

有人可以给我提示如何实现身份验证吗?

基于博客文章OData和Authentication –第4部分–服务器端挂钩,我创建了一种用于DataServices的扩展方法。 请记住,您仅通过HTTPS使用基本身份验证,否则您的密码将对其他用户可见,因为用户名/密码只是对base64进行解码的。 为了进行测试,您可以删除此检查, if (!context.Request.IsSecureConnection) return false;

用法:

public ProductsDataService : EntityFrameworkDataService<ProductsContext>
{
    private static validator = new UserValidator();
    public ProductsDataService()
    {
        this.UseBasicAuthentification("My Realm", validator);
    }

    private class UserValidator : IUserValidator
    {
        public IPrincipal Validate(string username, string password)
        {
            // just an example implementation
            if (!"1234".Equals(password)) retur null;
            return new GenericPrincipal(
                new GenericIdentity(username), "Admin", "User");
        }
    }
}

这是实现。 您只需要创建一个满足您需要的IUserValidator实现即可。

public static class DataServiceExtensions
{

    public static void UseBasicAuthentification<T>(
        this DataService<T> service, string realm, IUserValidator validator)
    {
        service.ProcessingPipeline.ProcessingRequest += (_sender, _e) =>
        {
            if (!Authenticate(_e.OperationContext, validator))
            {
                _e.OperationContext.ResponseHeaders.Add(
                     "WWW-Authenticate", "Basic realm=" + 
                        Convert.ToBase64String(
                        Encoding.UTF8.GetBytes(GlobalConfiguration.Realm)));
                throw new DataServiceException(401, "401 Unauthorized");
            }
        };
    }

    static bool Authenticate(DataServiceOperationContext context,
        IUserValidator validator)
    {
        if (!context.RequestHeaders.AllKeys.Contains("Authorization"))
            return false;

        // Remember claims based security should be only be 
        // used over HTTPS  
        if (!context.Request.IsSecureConnection)
            return false;

        string authHeader = context.RequestHeaders["Authorization"];

        IPrincipal principal = null;
        if (TryGetPrincipal(authHeader, validator, out principal))
        {
            //context.User = principal;
            return true;
        }
        return false;
    }

    private static bool TryGetPrincipal(string authHeader,
        IUserValidator validator, out IPrincipal principal)
    {
        var protocolParts = authHeader.Split(' ');
        if (protocolParts.Length != 2)
        {
            principal = null;
            return false;
        }
        else if (protocolParts[0] == "Basic")
        {

            var parameter = Encoding.UTF8.GetString(
                Convert.FromBase64String(protocolParts[1]));
            var parts = parameter.Split(':');

            if (parts.Length != 2)
            {
                principal = null;
                return false;
            }

            var username = parts[0];
            var password = parts[1];

            principal = validator.Validate(username, password);

            return principal != null;
        }
        else
        {
            principal = null;
            return false;
        }
    }

}

public interface IUserValidator
{
    IPrincipal Validate(string username, string password);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM