Pertanyaan Menambahkan autent HTTP dasar ke layanan REST WCF


Saya memiliki WCF HTTP REST Service dan saya mengikatnya dengan klien HTTP dalam bahasa pemrograman yang berbeda yang menulis HTTP kustomnya sendiri. Saya ingin menambahkan autentikasi otentikasi dasar WWW ke layanan WCF saya.

Metode saya terlihat seperti ini:

[WebInvoke(UriTemplate = "widgets", Method = "POST")]
public XElement CreateWidget(XElement e)   
{
...
}

Apakah mungkin bagi saya untuk entah bagaimana menyaring permintaan HTTP yang masuk sehingga saya dapat memeriksa string autentikasi Dasar yang valid sebelum menyentuh masing-masing metode REST seperti CreateWidget atas? Catatan: Info auth saya adalah stord dalam database saya.

Pada dasarnya saya ingin memeriksa ini di header permintaan: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== dan kemudian saya sendiri dapat mengurai string itu dan memvalidasi u / p dalam database.

File web.config adalah sebagai berikut:

<?xml version="1.0"?>
<configuration>

  <connectionStrings>
    <add name="DatabaseConnectionString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Database;Integrated Security=True" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpRuntime maxRequestLength="10485760" />
  </system.web>

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </modules>
  </system.webServer>

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true" maxReceivedMessageSize="1048576" maxBufferSize="1048576" />
      </webHttpEndpoint>
    </standardEndpoints>
  </system.serviceModel>

</configuration>

9
2018-01-17 17:01


asal


Jawaban:


Saya juga tertarik pada otentikasi kustom dalam layanan RST HTTP WCF dan akhirnya berhasil.

Itu dikatakan kode saya akan memberi Anda cara untuk membuatnya bekerja, tapi saya sarankan membaca panduan ini yang menjelaskan semuanya secara lebih mendalam: http://wcfsecurityguide.codeplex.com/

Pertama, ubah system.web bagian dari Web.Config Anda untuk terlihat seperti ini:

<system.web>
  <compilation debug="true" targetFramework="4.0" />
  <httpRuntime maxRequestLength="10485760" />
  <authentication mode="None"></authentication>
  <httpModules>
    <add name="BasicAuthenticationModule" type="YourNamespace.UserNameAuthenticator" />
  </httpModules>
</system.web>

Kemudian tambahkan file lain ke proyek Anda: UserNameAuthenticator.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Security.Principal;
using System.ServiceModel.Activation;

namespace YourNamespace
{
    public class UserNameAuthenticator : IHttpModule
    {
        public void Dispose()
        {
        }

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

        public bool CustomAuth(string username, string password)
        {
            //TODO: Implement your custom auth logic here
            return true;
        }

        public string[] GetCustomRoles(string username)
        {
            return new string[] { "read", "write" };
        }

        public void OnAuthorizationRequest(object source, EventArgs eventArgs)
        {
            HttpApplication app = (HttpApplication)source;
            //If you want to handle authorization differently from authentication
        }

        public void OnAuthenticateRequest(object source, EventArgs eventArgs)
        {
            HttpApplication app = (HttpApplication)source;
            //the Authorization header is checked if present
            string authHeader = app.Request.Headers["Authorization"];
            if (!string.IsNullOrEmpty(authHeader))
            {
                string authStr = app.Request.Headers["Authorization"];
                if (authStr == null || authStr.Length == 0)
                {
                    // No credentials; anonymous request
                    return;
                }
                authStr = authStr.Trim();
                if (authStr.IndexOf("Basic", 0) != 0)
                {
                    //header not correct we do not authenticate
                    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];
                //the user is validated against the SqlMemberShipProvider
                //If it is validated then the roles are retrieved from the
                //role provider and a generic principal is created
                //the generic principal is assigned to the user context
                // of the application
                if (CustomAuth(username, password))
                {
                    string[] roles = GetCustomRoles(username);
                    app.Context.User = new GenericPrincipal(new
                    GenericIdentity(username, "Membership Provider"), roles);
                }
                else
                {
                    DenyAccess(app);
                    return;
                }
            }
            else
            {
                //the authorization header is not present
                //the status of response is set to 401 and it ended
                //the end request will check if it is 401 and add
                //the authentication header so the client knows
                //it needs to send credentials to authenticate
                app.Response.StatusCode = 401;
                app.Response.End();
            }
        }

        public void OnEndRequest(object source, EventArgs eventArgs)
        {
            if (HttpContext.Current.Response.StatusCode == 401)
            {
                //if the status is 401 the WWW-Authenticated is added to
                //the response so client knows it needs to send credentials
                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";
            // error not authenticated
            app.Response.Write("401 Access Denied");
            app.CompleteRequest();
        }
    } // End Class
} //End Namespace

8
2018-01-18 22:02



Saya memiliki masalah serupa dan menemukan banyak pendekatan yang berbeda, terutama panggilan lintas domain, bersama dengan otentikasi dasar tampaknya menjadi sedikit tantangan. Jquery misalnya pertama mengeluarkan panggilan OPSI untuk memverifikasi bahwa POST diperbolehkan. Wcf biasanya menolak permintaan ini dan Anda mendapatkan kesalahan aneh.

Saya akhirnya berhasil dan Anda dapat mengunduh kode sampel dari blog saya: http://sameproblemmorecode.blogspot.com/2011/10/creating-secure-restfull-wcf-service.html


3
2017-10-30 21:02



Hanya untuk menambahkan ini, Chrome tidak akan memuat dialog masuk kecuali Anda mengubah "BasicRealm" menjadi "BasicRealm = site" dalam metode OnEndRequest:

    public void OnEndRequest(object source, EventArgs eventArgs)
    {
        if (HttpContext.Current.Response.StatusCode == 401)
        {
            //if the status is 401 the WWW-Authenticated is added to 
            //the response so client knows it needs to send credentials 
            HttpContext context = HttpContext.Current;
            context.Response.StatusCode = 401;
            context.Response.AddHeader("WWW-Authenticate", "Basic Realm=site");
        }
    }

Dan terima kasih, ini adalah solusi yang sederhana.


2
2017-10-08 21:58