2012-06-02 31 views
11

asmxウェブサービスでユーザ名とパスワードの検証を使用して基本認証を実装したいと考えています。
私はWCFを使いたくないのですが、これは安全な方法ではないことがわかりますしかし、httpsを使わずに基本認証を使用する必要があります。Asmx Webサービスの基本認証

私のWebサービスは、このようなものです:

[WebService(Namespace = "http://www.mywebsite.com/")] 
public class Service1 
{ 
    [WebMethod] 
    public string HelloWorld() 
    { 
     return "Hello world"; 
    } 
} 

そして、私はこのカスタムHttpModuleを使用します。

public class BasicAuthHttpModule : IHttpModule 
{ 
    void IHttpModule.Init(HttpApplication context) 
    { 
     context.AuthenticateRequest += new EventHandler(OnAuthenticateRequest); 
    } 

    void OnAuthenticateRequest(object sender, EventArgs e) 
    { 
     string header = HttpContext.Current.Request.Headers["Authorization"]; 

     if (header != null && header.StartsWith("Basic")) //if has header 
     { 
      string encodedUserPass = header.Substring(6).Trim(); //remove the "Basic" 
      Encoding encoding = Encoding.GetEncoding("iso-8859-1"); 
      string userPass = encoding.GetString(Convert.FromBase64String(encodedUserPass)); 
      string[] credentials = userPass.Split(':'); 
      string username = credentials[0]; 
      string password = credentials[1]; 

      if(!MyUserValidator.Validate(username, password)) 
      { 
       HttpContext.Current.Response.StatusCode = 401; 
       HttpContext.Current.Response.End(); 
      } 
     } 
     else 
     { 
      //send request header for the 1st round 
      HttpContext context = HttpContext.Current; 
      context.Response.StatusCode = 401; 
      context.Response.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", string.Empty)); 
     } 
    } 

    void IHttpModule.Dispose() 
    { 
    } 
} 

そして、私はこれを使用してweb.configファイルで:

<?xml version="1.0"?> 
<configuration> 
    <appSettings/> 
    <connectionStrings/> 
    <system.web> 
     <customErrors mode="Off" /> 
     <compilation debug="true" targetFramework="4.0"/> 
     <authentication mode="None"/> 
    </system.web> 
    <system.webServer> 
     <modules runAllManagedModulesForAllRequests="true"> 
      <add name="BasicAuthHttpModule" 
       type="AuthService.BasicAuthHttpModule, AuthService" /> 
     </modules> 
    </system.webServer> 
</configuration>  

呼び出しコード:

static void Main(string[] args) 
{ 
    var proxy = new Service1.Service1() 
        { 
         Credentials = new NetworkCredential("user1", "[email protected]"), 
         PreAuthenticate = true 
        }; 
    try 
    { 
     var result = proxy.HelloWorld(); 
     Console.WriteLine(result); 
    } 
    catch (Exception e) 
    { 
     Console.WriteLine(e.Message); 
    } 
    Console.ReadKey(); 
} 

このWebサービスを使用すると、サービスは基本認証を要求しますが、OnAuthenticateRequestメソッドの変数headerは常にnullで、MyUserValidator.Validate()は実行されません。

EDIT

シオマネキ結果:

POST http://www.mywebsite.com/Service1.asmx HTTP/1.1 
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.4927) 
VsDebuggerCausalityData: uIDPo+drc57U77xGu/ZaOdYvw6IAAAAA8AjKQNpkV06FEWDEs2Oja2C+h3kM7dlDvnFfE1VlIIIACQAA 
Content-Type: text/xml; charset=utf-8 
SOAPAction: "http://www.mywebsite.com/HelloWorld" 
Host: www.mywebsite.com 
Content-Length: 291 
Expect: 100-continue 
Connection: Keep-Alive 

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><HelloWorld xmlns="http://www.mywebsite.com/" /></soap:Body></soap:Envelope> 
HTTP/1.1 401 Unauthorized 
Cache-Control: private 
Content-Type: text/html 
Server: Microsoft-IIS/7.5 
WWW-Authenticate: Basic realm="" 
X-AspNet-Version: 4.0.30319 
WWW-Authenticate: Basic realm="www.mywebsite.com" 
X-Powered-By: ASP.NET 
Date: Sun, 03 Jun 2012 07:14:40 GMT 
Content-Length: 1293 
------------------------------------------------------------------ 

POST http://www.mywebsite.com/Service1.asmx HTTP/1.1 
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.4927) 
VsDebuggerCausalityData: uIDPo+drc57U77xGu/ZaOdYvw6IAAAAA8AjKQNpkV06FEWDEs2Oja2C+h3kM7dlDvnFfE1VlIIIACQAA 
Content-Type: text/xml; charset=utf-8 
SOAPAction: "http://www.mywebsite.com/HelloWorld" 
Authorization: Basic dXNlcjE6cEBzc3cwcmQ= 
Host: www.mywebsite.com 
Content-Length: 291 
Expect: 100-continue 

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><HelloWorld xmlns="http://www.mywebsite.com/" /></soap:Body></soap:Envelope> 
HTTP/1.1 401 Unauthorized 
Content-Type: text/html 
Server: Microsoft-IIS/7.5 
WWW-Authenticate: Basic realm="www.mywebsite.com" 
X-Powered-By: ASP.NET 
Date: Sun, 03 Jun 2012 07:14:41 GMT 
Content-Length: 1293 
------------------------------------------------------------------ 
+0

実行されることはありませんか?これを確認するためにブレークポイントを設定しましたか? –

+0

はい私は確かです。常に 'else'ブロックが実行されています –

+0

私はそれを質問に追加しました。 –

答えて

10

Rick Strahl's BlogからごカスタムHttpMoこれにduleコード:

public class BasicAuthHttpModule : IHttpModule 
{ 
    public void Dispose() 
    { 
    } 

    public void Init(HttpApplication application) 
    { 
     application.AuthenticateRequest += new 
      EventHandler(this.OnAuthenticateRequest); 
     application.EndRequest += new 
      EventHandler(this.OnEndRequest); 
    } 

    public void OnAuthenticateRequest(object source, EventArgs 
         eventArgs) 
    { 
     HttpApplication app = (HttpApplication)source; 

     string authHeader = app.Request.Headers["Authorization"]; 
     if (!string.IsNullOrEmpty(authHeader)) 
     { 
      string authStr = app.Request.Headers["Authorization"]; 

      if (authStr == null || authStr.Length == 0) 
      { 
       return; 
      } 

      authStr = authStr.Trim(); 
      if (authStr.IndexOf("Basic", 0) != 0) 
      { 
       return; 
      } 

      authStr = authStr.Trim(); 

      string encodedCredentials = authStr.Substring(6); 

      byte[] decodedBytes = 
      Convert.FromBase64String(encodedCredentials); 
      string s = new ASCIIEncoding().GetString(decodedBytes); 

      string[] userPass = s.Split(new char[] { ':' }); 
      string username = userPass[0]; 
      string password = userPass[1]; 

      if (!MyUserValidator.Validate(username, password)) 
      { 
       DenyAccess(app); 
       return; 
      } 
     } 
     else 
     { 
      app.Response.StatusCode = 401; 
      app.Response.End(); 
     } 
    } 
    public void OnEndRequest(object source, EventArgs eventArgs) 
    { 
     if (HttpContext.Current.Response.StatusCode == 401) 
     { 
      HttpContext context = HttpContext.Current; 
      context.Response.StatusCode = 401; 
      context.Response.AddHeader("WWW-Authenticate", "Basic Realm"); 
     } 
    } 

    private void DenyAccess(HttpApplication app) 
    { 
     app.Response.StatusCode = 401; 
     app.Response.StatusDescription = "Access Denied"; 
     app.Response.Write("401 Access Denied"); 
     app.CompleteRequest(); 
    } 
} 

その後Anonymous authenticationを有効にしてIISであなたのウェブサイトのためのBasicDigestWindows認証を無効にします。

注:この実装はWCFでも動作します。

+0

私の場合、匿名認証も無効にする必要がありました。 ' <認証> 。 .. – Evilripper

+0

私にとっては、「統合アプリケーションプールモード」を使用するアプリケーションプールでのみ動作しています。古典モードでは動作しません。しかし、私はなぜ正確に説明することはできません... – Lopo

+0

私のために働いた...私はweb.configセクションを編集する必要がありました。 type = "AuthService.BasicAuthHttpModule、AuthService"からtype = "BasicAuthHttpModule"にタイプを変更します。 BasicAuthHttpModuleを追加したクラスに名前空間が含まれていないことを確認しました。 –

1

あなたが初めて手動でヘッダーを送信必要があると思わ:変更

string url = "http://rasnote/wconnect/admin/wc.wc?_maintain~ShowStatus"; 
    HttpWebRequest req = HttpWebRequest.Create(url) as HttpWebRequest; 

    string user = "ricks"; 
    string pwd = "secret"; 
    string domain = "www.west-wind.com"; 

    string auth = "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(user + ":" + pwd)); 
    req.PreAuthenticate = true; 
    req.Headers.Add("Authorization", auth); 
    req.UserAgent = ": Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 4.0.20506)"; 
    WebResponse resp = req.GetResponse(); 
    resp.Close(); 
+0

私はこのコードを使用して、 'WebResponse resp = req.GetResponse(); 'の認証エラーを返します。 –

+0

preauthenticateに関する記事の残りの部分は続けましたか? –

関連する問題