【问题标题】:How to implement WebServiceHost Authentication?如何实现 WebServiceHost 身份验证?
【发布时间】:2013-04-10 01:43:36
【问题描述】:

我知道 webservicehost 类上的身份验证不完全符合身份验证标准(当用户输入不正确的凭据时,返回 403 禁止,而不是提示输入另一组凭据)。

我仍然希望实现此基本身份验证(会话开始时的用户名和密码,不需要 HTTPS - 见下图),因为它适合我对小型家庭项目的需求。

myService 的代码如下:

Imports System.IO
Imports System.Text
Imports System.ServiceModel
Imports System.ServiceModel.Web
Imports System.ServiceModel.Channels

<ServiceContract()>
Public Class myService
    <OperationContract(), WebGet(UriTemplate:="/xml/{argument1}/{argument2}")>
    Public Function XML(argument1 As String, argument2 As String) As Stream
        requestCounter += 1
        Console.WriteLine("xml data request at " & DateTime.Now.ToString() & ", request count= " & requestCounter)
        Console.WriteLine(WebOperationContext.Current.IncomingRequest.UserAgent.ToString())
        Return _ReturnXML("<xmlresponse><data><argument1>" & argument1 & "</argument1><argument2>" & argument2 & "</argument2></data><server><serverlivesince>" & serverStart.ToString() & "</serverlivesince><pageservetime>" & DateTime.Now.ToString() & "</pageservetime><requestcount>" & requestCounter & "</requestcount></server></xmlresponse>")
        'returns the first two parameters, and the time and date
    End Function

    Private Shared Function _ReturnXML(_result As String) As Stream
        Dim data = Encoding.UTF8.GetBytes(_result)

        WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml; charset=utf-8"
        WebOperationContext.Current.OutgoingResponse.ContentLength = data.Length

        Return New MemoryStream(data)
    End Function
End Class

然后我有类似的代码来返回 HTML 以及接受其他参数组合。

在我的 Main 类中,我实例化并打开了这个服务:

Dim varWebService = New WebServiceHost(GetType(MyWebService), New Uri("http://0.0.0.0/"))
varWebService.Open()

谁能提供代码来实现这个简单的身份验证?或者指点我一个详尽的教程?感谢您的帮助

【问题讨论】:

  • 你尝试了什么?你得到了什么?你期待什么?
  • 我还没有尝试过,甚至不知道如何去做
  • Stack Overflow 通常对有特定问题的问题很友好。对于征求意见的问题,我们往往会皱眉头。

标签: windows vb.net web-services http webservicehost


【解决方案1】:

您可以通过继承它来编写自定义 WebServiceHost 并更改一些默认参数,如下所示。

您的代码中唯一的变化是

Dim varWebService = New AuthenticatedWebServiceHost(GetType(MyWebService), New Uri("http://0.0.0.0/"))

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IdentityModel;
using System.IdentityModel.Selectors;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Security;
using System.ServiceModel.Description;

namespace StackOverflow
{
    public class AuthenticatedWebServiceHost : WebServiceHost
    {
        public AuthenticatedWebServiceHost(Type type, Uri url)
        {
            IDictionary<string, ContractDescription> desc = null;
            base.InitializeDescription(type, new UriSchemeKeyedCollection());
            base.CreateDescription(out desc);
            var val = desc.Values.First();

            WebHttpBinding binding = new WebHttpBinding();
            binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

            base.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
            base.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNamePasswordValidator();

            base.AddServiceEndpoint(val.ContractType, binding, url);
        }

        //Possible next question:
        //"How can I get the name of the authenticated user?"
        public static string UserName
        {
            get
            {
                if (OperationContext.Current == null) return null;
                if (OperationContext.Current.ServiceSecurityContext == null) return null;
                if (OperationContext.Current.ServiceSecurityContext.PrimaryIdentity == null) return null;
                return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
            }
        }



        public class CustomUserNamePasswordValidator : UserNamePasswordValidator
        {
            public override void Validate(string userName, string password)
            {
                //Your logic to validate username/password
                if (userName != password)
                    throw new SecurityAccessDeniedException();
            }
        }
    }
}

【讨论】:

  • 我实际上似乎无法让它工作。您是否有机会提供一个包含示例函数的工作示例项目?谢谢,
【解决方案2】:

I4V 提供的答案就像一个魅力,转换为 VB 并在下面复制,以防其他人在花费大量时间搜索网络后需要它。

调用它的线路按照I4V提供的代码。

Dim varWebService = New AuthenticatedWebServiceHost(GetType(MyWebService), New Uri("http://0.0.0.0/"))

VB.Net 代码

Imports System.IdentityModel.Selectors
Imports System.ServiceModel
Imports System.ServiceModel.Description
Imports System.ServiceModel.Security
Imports System.ServiceModel.Web

Public Class AuthenticatedWebServiceHost
    Inherits WebServiceHost

    Public Sub New(ByVal type As Type, ByVal url As Uri)
        Dim desc As IDictionary(Of String, ContractDescription) = Nothing
        MyBase.InitializeDescription(type, New UriSchemeKeyedCollection())
        MyBase.CreateDescription(desc)
        Dim val = desc.Values.First()
        Dim binding As WebHttpBinding = New WebHttpBinding()
        binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic
        MyBase.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom
        MyBase.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = New CustomUserNamePasswordValidator()
        MyBase.AddServiceEndpoint(val.ContractType, binding, url)
    End Sub

    Public Shared ReadOnly Property UserName As String
        Get
            If OperationContext.Current Is Nothing Then Return Nothing
            If OperationContext.Current.ServiceSecurityContext Is Nothing Then Return Nothing
            If OperationContext.Current.ServiceSecurityContext.PrimaryIdentity Is Nothing Then Return Nothing
            Return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name
        End Get
    End Property

    Public Class CustomUserNamePasswordValidator
        Inherits UserNamePasswordValidator

        Public Overrides Sub Validate(ByVal userName As String, ByVal password As String)
            If userName <> password Then Throw New SecurityAccessDeniedException()
        End Sub
    End Class
End Class

【讨论】:

    【解决方案3】:

    Shaydo,你是最棒的!谢谢!这就是我搜索了数周的内容! 我扩展了 vb 代码以便将其与 https 一起使用: VB.NET:

    Public Class AuthenticatedWebServiceHost
       Inherits WebServiceHost
        Public Sub New(ByVal type As Type, ByVal url As Uri, MyThumbprint As String)
            Dim desc As IDictionary(Of String, ContractDescription) = Nothing
            MyBase.InitializeDescription(type, New UriSchemeKeyedCollection())
            MyBase.CreateDescription(desc)
            Dim val = desc.Values.First()
            Dim binding As WebHttpBinding = New WebHttpBinding()
            'binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly
            binding.Security.Mode = BasicHttpsSecurityMode.TransportWithMessageCredential
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic
            MyBase.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom
            MyBase.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = New CustomUserNamePasswordValidator()
            MyBase.Credentials.ClientCertificate.SetCertificate(System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine, System.Security.Cryptography.X509Certificates.StoreName.My, System.Security.Cryptography.X509Certificates.X509FindType.FindByThumbprint, MyThumbprint)
            MyBase.AddServiceEndpoint(val.ContractType, binding, url)
        End Sub
    
        Public Shared ReadOnly Property UserName As String
            Get
                If OperationContext.Current Is Nothing Then Return Nothing
                If OperationContext.Current.ServiceSecurityContext Is Nothing Then Return Nothing
                If OperationContext.Current.ServiceSecurityContext.PrimaryIdentity Is Nothing Then Return Nothing
                Return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name
            End Get
        End Property
    
        Public Class CustomUserNamePasswordValidator
            Inherits UserNamePasswordValidator
            Public Overrides Sub Validate(ByVal userName As String, ByVal password As String)
                If userName <> password Then
                    Console.WriteLine("Error: Access denied")
                    Throw New SecurityAccessDeniedException()
                End If
            End Sub
        End Class
    End Class
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-15
      • 2018-09-29
      • 2018-04-09
      • 2019-04-11
      相关资源
      最近更新 更多