添加基本​​HTTP认证到WCF REST服务 [英] Adding basic HTTP auth to a WCF REST service

查看:172
本文介绍了添加基本​​HTTP认证到WCF REST服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个WCF HTTP REST服务,我扎入其与HTTP客户端在谁写自己的自定义HTTP不同的编程语言。
我想WWW验证基本认证支持添加到我的WCF服务。

我的方法是这样的:

  [WebInvoke(UriTemplate =小工具,方法=POST)]
公众的XElement CreateWidget(的XElement E)
{
...
}

是否有可能我以某种方式过滤传入的HTTP请求,所以我可以检查一个有效的基本身份验证字符串它击中每个REST方法,如 CreateWidget 上面过吗?
注:我的验证信息是在我的数据库斯图尔

基本上我想在请求头检查此:
授权:基本QWxhZGRpbjpvcGVuIHNlc2FtZQ == ,然后我可以自己分析该字符串并验证U / p在数据库

在Web.config文件如下:

 <?XML版本=1.0&GT?;
<结构>  <&是connectionStrings GT;
    <添加名称=DatabaseConnectionString的connectionString =数据源= \\ SQLEX $ P $干燥综合征;初始目录=数据库;集成安全性=真的providerName =System.Data.SqlClient的/>
  < /&是connectionStrings GT;
  <&的System.Web GT;
    <编译调试=真targetFramework =4.0/>
    <的httpRuntime的maxRequestLength =10485760/>
  < /system.web>  < system.webServer>
    <模块runAllManagedModulesForAllRequests =真正的>
      <添加名称=UrlRoutingModuleTYPE =System.Web.Routing.UrlRoutingModule,System.Web程序,版本= 4.0.0.0,文化=中性公钥= b03f5f7f11d50a3a/>
    < /模块>
  < /system.webServer>  < system.serviceModel>
    < serviceHostingEnvironment aspNetCompatibilityEnabled =真/>
    < standardEndpoints>
      < webHttpEndpoint>
        < standardEndpoint NAME =helpEnabled =真automaticFormatSelectionEnabled =真maxReceivedMessageSize =1048576MAXBUFFERSIZE =1048576/>
      < / webHttpEndpoint>
    < / standardEndpoints>
  < /system.serviceModel>< /结构>


解决方案

我也是在一个HTTP REST WCF服务感兴趣的自定义身份验证,终于得到它的工作。

话虽这么说,我的code会给你一种方式来获得它的工作,但我建议阅读本指南,解释了更深入的一切:的 HTTP://wcfsecurityguide.$c$cplex.com/

首先,改变你的web.config的的System.Web 部分看起来是这样的:

 <&的System.Web GT;
  <编译调试=真targetFramework =4.0/>
  <的httpRuntime的maxRequestLength =10485760/>
  <身份验证模式=无>< /认证>
  <&的HttpModules GT;
    <添加名称=BasicAuthenticationModuleTYPE =YourNamespace.UserNameAuthenticator/>
  < /&的HttpModules GT;
< /system.web>

接着另外一个文件添加到您的项目:UserNameAuthenticator.cs

 使用系统;
使用System.Collections.Generic;
使用System.Text;
使用的System.Web;
使用System.Web.Security;
使用System.Security.Principal;
使用System.ServiceModel.Activati​​on;命名空间YourNamespace
{
    公共类UserNameAuthenticator:IHttpModule的
    {
        公共无效的Dispose()
        {
        }        公共无效初始化(HttpApplication的应用程序)
        {
            application.AuthenticateRequest + =新的EventHandler(this.OnAuthenticateRequest);
            application.AuthorizeRequest + =新的EventHandler(this.OnAuthorizationRequest);
            application.EndRequest + =新的EventHandler(this.OnEndRequest);
        }        公共BOOL CustomAuth(用户名字符串,字符串密码)
        {
            // TODO:在这里实现自定义的身份验证逻辑
            返回true;
        }        公共字符串[] GetCustomRoles(用户名字符串)
        {
            返回新的字符串[] {读,写};
        }        公共无效OnAuthorizationRequest(对象源,EventArgs的EventArgs的)
        {
            HttpApplication的应用程序=(HttpApplication的)来源;
            //如果你想从不同的认证授权办理
        }        公共无效OnAuthenticateRequest(对象源,EventArgs的EventArgs的)
        {
            HttpApplication的应用程序=(HttpApplication的)来源;
            //授权头如果选中present
            字符串authHeader = app.Request.Headers [授权];
            如果(!string.IsNullOrEmpty(authHeader))
            {
                字符串authStr = app.Request.Headers [授权];
                如果(authStr == NULL || authStr.Length == 0)
                {
                    //无凭据;匿名请求
                    返回;
                }
                authStr = authStr.Trim();
                如果(authStr.IndexOf(基本,0)!= 0)
                {
                    //头不正确的,我们不进行身份验证
                    返回;
                }                authStr = authStr.Trim();
                字符串连接codedCredentials = authStr.Substring(6);
                字节[]德codedBytes = Convert.FromBase64String(EN codedCredentials);
                字符串s =新ASCIIEncoding()的GetString(DE codedBytes)。
                字符串[] =为userpass s.Split(新的char [] {':'});
                字符串的用户名=为userpass [0];
                字符串密码=为userpass [1];
                //用户对SqlMembershipProvider的验证
                //如果被验证则角色从检索
                //角色提供程序并创建一个通用的主
                //通用主要被分配给用户上下文
                //应用程序的
                如果(CustomAuth(用户名,密码))
                {
                    字符串[] =角色GetCustomRoles(用户名);
                    app.Context.User =新的GenericPrincipal(新
                    GenericIdentity(用户名,会员提供商),角色);
                }
                其他
                {
                    DenyAccess(应用);
                    返回;
                }
            }
            其他
            {
                //授权头不是present
                //响应的状态被设置为401和它结束
                //结束请求将检查它是否是401,并添加
                //认证头让客户端知道
                //需要发送凭据进行身份验证
                app.Response.Status code = 401;
                app.Response.End();
            }
        }        公共无效OnEndRequest(对象源,EventArgs的EventArgs的)
        {
            如果(HttpContext.Current.Response.Status code == 401)
            {
                //如果状态401中的WWW的身份验证被添加到
                //所以客户端的响应知道它需要发送凭据
                HttpContext的背景下= HttpContext.Current;
                context.Response.Status code = 401;
                context.Response.AddHeader(WWW身份验证,基本领域);
            }
        }
        私人无效DenyAccess(HttpApplication的应用程序)
        {
            app.Response.Status code = 401;
            app.Response.StatusDescription =拒绝访问;
            //错误未通过身份验证
            app.Response.Write(401拒绝访问);
            app.CompleteRequest();
        }
    } //末级
} //结束名称空间

I have a WCF HTTP REST Service and I tie into it with an HTTP client in a different programming language who writes its own custom HTTP. I would like to add WWW-Authenticate basic authentication support to my WCF service.

My methods look like this:

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

Is it possible for me to somehow filter incoming HTTP requests so I can check for a valid Basic auth string before it hits each of the REST methods like CreateWidget above? Note: My auth info is stord in my database.

Basically I want to check for this in the request headers: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== and then I can myself parse that string and validate the u/p in the database.

The web.config file is as follows:

<?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>

解决方案

I was also interested in custom authentication in a REST HTTP WCF service and finally got it to work.

That being said my code will give you a way to get it working, but I recommend reading this guide which explains everything in more depth: http://wcfsecurityguide.codeplex.com/

First, change the system.web portion of your Web.Config to look like this:

<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>

Then add another file to your project: 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

这篇关于添加基本​​HTTP认证到WCF REST服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆