解决方案是使用MSDN和CodeProject提供的混合代码编写自己的http模块.包括自己的MS错误修复程序,然后将此自定义soap标头添加到Web服务.
<SoapHeader("Authentication", Required:=True)>
Run Code Online (Sandbox Code Playgroud)
这是模块:
Imports System.Web
Imports System.Web.Services.Protocols
' http://msdn.microsoft.com/en-us/library/9z52by6a.aspx
' http://msdn.microsoft.com/en-us/library/9z52by6a(VS.80).aspx
' http://www.codeproject.com/KB/cpp/authforwebservices.aspx
' http://aleemkhan.wordpress.com/2007/09/18/using-wse-30-for-web-service-authentication/
' http://www.codeproject.com/KB/WCF/CustomUserNamePassAuth2.aspx
' http://www.codeproject.com/KB/WCF/CustomUserNamePassAuth2.aspx
' http://www.codeproject.com/KB/webservices/WS-Security.aspx
'Public NotInheritable Class WebServiceAuthenticationModule
Public Class WebServiceAuthenticationModule
Implements System.Web.IHttpModule
Protected Delegate Sub WebServiceAuthenticationEventHandler(ByVal sender As [Object], ByVal e As WebServiceAuthenticationEvent)
Protected _eventHandler As WebServiceAuthenticationEventHandler = Nothing
Protected Custom Event Authenticate As WebServiceAuthenticationEventHandler
AddHandler(ByVal value As WebServiceAuthenticationEventHandler)
_eventHandler = value
End AddHandler
RemoveHandler(ByVal value As WebServiceAuthenticationEventHandler)
_eventHandler = value
End RemoveHandler
RaiseEvent(ByVal sender As Object,
ByVal e As WebServiceAuthenticationEvent)
End RaiseEvent
End Event
Protected app As HttpApplication
Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
app = context
context.Context.Response.Write("<h1>Test</h1>")
AddHandler app.AuthenticateRequest, AddressOf Me.OnEnter
End Sub
Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
' add clean-up code here if required
End Sub
Protected Sub OnAuthenticate(ByVal e As WebServiceAuthenticationEvent)
If _eventHandler Is Nothing Then
Return
End If
_eventHandler(Me, e)
If Not (e.User Is Nothing) Then
e.Context.User = e.Principal
End If
End Sub 'OnAuthenticate
Public ReadOnly Property ModuleName() As String
Get
Return "WebServiceAuthentication"
End Get
End Property
Sub OnEnter(ByVal [source] As [Object], ByVal eventArgs As EventArgs)
'Dim app As HttpApplication = CType([source], HttpApplication)
'app = CType([source], HttpApplication)
Dim context As HttpContext = app.Context
Dim HttpStream As System.IO.Stream = context.Request.InputStream
' Save the current position of stream.
Dim posStream As Long = HttpStream.Position
' If the request contains an HTTP_SOAPACTION
' header, look at this message.
'For Each str As String In context.Request.ServerVariables.AllKeys
'If context.Request.ServerVariables(Str) IsNot Nothing Then
'context.Response.Write("<h1>" + Str() + "= " + context.Request.ServerVariables(Str) + "</h1>")
'End If
'Next
If context.Request.ServerVariables("HTTP_SOAPACTION") Is Nothing Then
'context.Response.End()
Return
'Else
'MsgBox(New System.IO.StreamReader(context.Request.InputStream).ReadToEnd())
End If
' Load the body of the HTTP message
' into an XML document.
Dim dom As New System.Xml.XmlDocument()
Dim soapUser As String
Dim soapPassword As String
Try
dom.Load(HttpStream)
'dom.Save("C:\Users\Administrator\Desktop\SoapRequest.xml")
' Reset the stream position.
HttpStream.Position = posStream
' Bind to the Authentication header.
soapUser = dom.GetElementsByTagName("Username").Item(0).InnerText
soapPassword = dom.GetElementsByTagName("Password").Item(0).InnerText
Catch e As Exception
' Reset the position of stream.
HttpStream.Position = posStream
' Throw a SOAP exception.
Dim name As New System.Xml.XmlQualifiedName("Load")
Dim ssoapException As New SoapException("Unable to read SOAP request", name, e)
context.Response.StatusCode = System.Net.HttpStatusCode.Unauthorized
context.Response.StatusDescription = "Access denied."
' context.Response.Write(ssoapException.ToString())
'Dim x As New System.Xml.Serialization.XmlSerializer(GetType(SoapException))
'context.Response.ContentType = "text/xml"
'x.Serialize(context.Response.OutputStream, ssoapException)
'Throw ssoapException
context.Response.End()
End Try
' Raise the custom global.asax event.
OnAuthenticate(New WebServiceAuthenticationEvent(context, soapUser, soapPassword))
Return
End Sub 'OnEnter
End Class ' WebServiceAuthenticationModule
Run Code Online (Sandbox Code Playgroud)
如果您仍在使用 ASP.NET SOAP Web 服务,那么满足 IMO 要求的最简单方法是将 ASP.NET 表单身份验证与成员资格数据库结合使用。如果您刚开始,我建议您使用 WCF - 如果您不能/或不会这样做,那么这篇文章适用于“经典”ASP.NET SOAP Web 服务。
要将 Forms 身份验证添加到 Web 服务:
像对任何其他网站一样对其进行配置,但将其设置为允许所有人访问:
<authorization>
<allow users="*"/>
</authorization>
Run Code Online (Sandbox Code Playgroud)实现登录/注销方法并在登录方法中发出身份验证票。对 Web 服务的进一步请求然后可以使用颁发的身份验证票证。
然后您可以使用您想要保护的所有其他网络方法进行装饰
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
如果客户端未通过身份验证,这些方法现在将引发安全异常。
受保护方法的示例:
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
[WebMethod(Description = "Your protected method")]
public string Foo()
{
return "bar";
}
Run Code Online (Sandbox Code Playgroud)
登录方法示例:
[WebMethod(Description = "Login to start a session")]
public bool Login(string userName, string password)
{
if (!Membership.Provider.ValidateUser(userName, password))
return false;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1,
userName,
DateTime.Now,
DateTime.Now.AddMinutes(500),
false,
FormsAuthentication.FormsCookiePath);// Path cookie valid for
// Encrypt the cookie using the machine key for secure transport
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, // Name of auth cookie
hash); // Hashed ticket
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent)
cookie.Expires = ticket.Expiration;
// Add the cookie to the list for outgoing response
if(HttpContext.Current !=null)
HttpContext.Current.Response.Cookies.Add(cookie);
FormsAuthentication.SetAuthCookie(userName, true);
return true;
}
Run Code Online (Sandbox Code Playgroud)