我知道webservicehost类上的身份validation不完全符合身份validation标准(返回403禁止,而不是在用户input不正确凭据时提示input另一组凭据)。
我仍然想要实现这个基本的身份validation(会话开始时的用户名和密码,不需要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以及接受其他参数组合。
在我的主类我已经实例化,并打开此服务为:
Dim varWebService = New WebServiceHost(GetType(MyWebService), New Uri("http://0.0.0.0/")) varWebService.Open()
任何人都可以提供代码来实现这个简单的身份validation? 或者指点我一个彻底的教程? 谢谢你的帮助
您可以通过继承自定义的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(); } } } }