本文转自:https://blogs.msdn.microsoft.com/astoriateam/2010/07/21/odata-and-authentication-part-6-custom-basic-authentication/

You might remember, from Part 5, that Basic Authentication is built-in to IIS.

So why do we need ‘Custom’ Basic Authentication?

Well if you are happy using windows users and passwords you don’t.

That’s because the built-in Basic Authentication, uses the Basic Authentication protocol, to authenticate against the windows user database.

If however you have a custom user/password database, perhaps it’s part of your application database, then you need ‘Custom’ Basic Authentication.

How does basic auth work?

Basic authentication is a very simple authentication scheme, that should only be used in conjunction with SSL or in scenarios where security isn’t paramount.

If you look at how a basic authentication header is fabricated, you can see why it is NOT secure by itself:

var creds = “user” + “:” + “password”;
var bcreds = Encoding.ASCII.GetBytes(creds);
var base64Creds = Convert.ToBase64String(bcreds);
authorizationHeader = “Basic ” + base64Creds; Yes that’s right the username and password are Base64 encoded and shipped on the wire for the whole world to see, unless of course you are also using SSL for transport level security. Nevertheless many systems use basic authentication. So it’s worth adding to your arsenal. Server Code: Creating a Custom Basic Authentication Module: Creating a Custom Basic Authentication module should be no harder than cracking Basic Auth, i.e. it should be child’s play. We can use our HttpModule from Part 5 as a starting point: public class BasicAuthenticationModule: IHttpModule
{
public void Init(HttpApplication context)
{
context.AuthenticateRequest
+= new EventHandler(context_AuthenticateRequest);
}
void context_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
if (!BasicAuthenticationProvider.Authenticate(application.Context))
{
application.Context.Response.Status = “401 Unauthorized”;
application.Context.Response.StatusCode = 401;
application.Context.Response.AddHeader(“WWW-Authenticate”, “Basic”);
application.CompleteRequest();
}
}
public void Dispose() { }
} The only differences from Part 5 are:
•We’ve changed the name to BasicAuthenticationModule.
•We use a new BasicAuthenticationProvider to do the authentication.
•And if the logon fails we challenge using the “WWW-Authenticate” header. The final step is vital because without this clients that don’t send credentials by default – like HttpWebRequest and by extension DataServiceContext – won’t know to retry with the credentials when their first attempt fails. Implementing the BasicAuthenticationProvider: The Authenticate method is unchanged from our example in Part 5: public static bool Authenticate(HttpContext context)
{
if (!HttpContext.Current.Request.IsSecureConnection)
return false; if (!HttpContext.Current.Request.Headers.AllKeys.Contains(“Authorization”))
return false; string authHeader = HttpContext.Current.Request.Headers[“Authorization”]; IPrincipal principal;
if (TryGetPrincipal(authHeader, out principal))
{
HttpContext.Current.User = principal;
return true;
}
return false;
} Our new TryGetPrincipal method looks like this: private static bool TryGetPrincipal(string authHeader, out IPrincipal principal)
{
var creds = ParseAuthHeader(authHeader);
if (creds != null && TryGetPrincipal(creds, out principal))
return true; principal = null;
return false;
} As you can see it uses ParseAuthHeader to extract the credentials from the authHeader – so they can be checked against our custom user database in the other TryGetPrincipal overload: private static string[] ParseAuthHeader(string authHeader)
{
// Check this is a Basic Auth header
if (
authHeader == null ||
authHeader.Length == 0 ||
!authHeader.StartsWith(“Basic”)
) return null; // Pull out the Credentials with are seperated by ‘:’ and Base64 encoded
string base64Credentials = authHeader.Substring(6);
string[] credentials = Encoding.ASCII.GetString(
Convert.FromBase64String(base64Credentials)
).Split(new char[] { ‘:’ }); if (credentials.Length != 2 ||
string.IsNullOrEmpty(credentials[0]) ||
string.IsNullOrEmpty(credentials[0])
) return null; // Okay this is the credentials
return credentials;
} First this code checks that this is indeed a Basic auth header and then attempts to extract the Base64 encoded credentials from the header. If everything goes according to plan the array returned will have two elements: the username and the password. Next we check our ‘custom’ user database to see if those credentials are valid. In this toy example I have it completely hard coded: private static bool TryGetPrincipal(string[] creds,out IPrincipal principal)
{
if (creds[0] == “Administrator” && creds[1] == “SecurePassword”)
{
principal = new GenericPrincipal(
new GenericIdentity(“Administrator”),
new string[] {“Administrator”, “User”}
);
return true;
}
else if (creds[0] == “JoeBlogs” && creds[1] == “Password”)
{
principal = new GenericPrincipal(
new GenericIdentity(“JoeBlogs”),
new string[] {“User”}
);
return true;
}
else
{
principal = null;
return false;
}
} You’d probably want to check a database somewhere, but as you can see that should be pretty easy, all you need is a replace this method with whatever code you want. Registering our BasicAuthenticationModule: Finally you just need to do is add this to your WebConfig: <system.webServer>
<modules>
<add name=”BasicAuthenticationModule”
type=”SimpleService.BasicAuthenticationModule”/>
</modules>
</system.webServer> Allowing unauthenticated access: If you want to allow some unauthenticated access to your Data Service, you could change your BasicAuthenticationModule so it doesn’t ‘401’ if the Authenticate() returns false. Then if certain queries or updates actually require authentication or authentication, you could check HttpContext.Current.Request.IsAuthenticated or HttpContext.Current.Request.User in QueryInterceptors and ChangeInterceptors as necessary. This approach allows you to mix and match your level of security. See part 4 for more on QueryInterceptors. Client Code: When you try to connect to an OData service protected with Basic Authentication (Custom or built-in) you have two options: Using the DataServiceContext.Credentials: You can use a Credentials Cache like this. var serviceCreds = new NetworkCredential(“Administrator”, “SecurePassword”);
var cache = new CredentialCache();
var serviceUri = new Uri(“http://localhost/SimpleService”);
cache.Add(serviceUri, “Basic”, serviceCreds);
ctx.Credentials = cache; When you do this the first time Data Services attempts to connect to the Service the credentials aren’t sent – so a 401 is received. However so long as the service challenges using the “WWW-Authenticate” response header, it will seamlessly retry under the hood. Using the request headers directly: Another option is to just create and send the authentication header yourself. 1) Hook up to the DataServiceContext’s SendingRequest Event: ctx.SendingRequest +=new EventHandler<SendingRequestEventArgs>(OnSendingRequest); 2) Add the Basic Authentication Header to the request: static void OnSendingRequest(object sender, SendingRequestEventArgs e)
{
var creds = “user” + “:” + “password”;
var bcreds = Encoding.ASCII.GetBytes(creds);
var base64Creds = Convert.ToBase64String(bcreds);
e.RequestHeader.Add(“Authorization”, “Basic ” + base64Creds);
} As you can see this is pretty simple. And has the advantage that it will work even if the server doesn’t respond with a challenge (i.e. WWW-Authenticate header). Summary: You now know how to implement Basic Authentication over a custom credentials database and how to interact with a Basic Authentication protected service using the Data Service Client. Next up we’ll look at Forms Authentication in depth. Alex James
Program Manager
Microsoft.

[转]OData and Authentication – Part 6 – Custom Basic Authentication的更多相关文章

  1. [转]OData and Authentication – Part 5 – Custom HttpModules

    本文转自:https://blogs.msdn.microsoft.com/odatateam/2010/07/19/odata-and-authentication-part-5-custom-ht ...

  2. 一个HTTP Basic Authentication引发的异常

    这几天在做一个功能,其实很简单.就是调用几个外部的API,返回数据后进行组装然后成为新的接口.其中一个API是一个很奇葩的API,虽然是基于HTTP的,但既没有基于SOAP规范,也不是Restful风 ...

  3. Secure Spring REST API using Basic Authentication

    What is Basic Authentication? Traditional authentication approaches like login pages or session iden ...

  4. Atitit HTTP 认证机制基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)attilax总结

    Atitit HTTP认证机制基本验证 (Basic Authentication) 和摘要验证 (Digest Authentication)attilax总结 1.1. 最广泛使用的是基本验证 ( ...

  5. Nancy 学习-身份认证(Basic Authentication) 继续跨平台

    开源 示例代码:https://github.com/linezero/NancyDemo 前面讲解Nancy的进阶部分,现在来学习Nancy 的身份认证. 本篇主要讲解Basic Authentic ...

  6. HTTP Basic Authentication

    Client端发送请求, 要在发送请求的时候添加HTTP Basic Authentication认证信息到请求中,有两种方法:1. 在请求头中添加Authorization:    Authoriz ...

  7. Web services 安全 - HTTP Basic Authentication

    根据 RFC2617 的规定,HTTP 有两种标准的认证方式,即,BASIC 和 DIGEST.HTTP Basic Authentication 是指客户端必须使用用户名和密码在一个指定的域 (Re ...

  8. Web API 基于ASP.NET Identity的Basic Authentication

    今天给大家分享在Web API下,如何利用ASP.NET Identity实现基本认证(Basic Authentication),在博客园子搜索了一圈Web API的基本认证,基本都是做的Forms ...

  9. PYTHON实现HTTP基本认证(BASIC AUTHENTICATION)

    参考: http://www.voidspace.org.uk/python/articles/authentication.shtml#id20 http://zh.wikipedia.org/wi ...

随机推荐

  1. leetcode 移除元素

    给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成 ...

  2. Web开发利器Webstorm导入多个文件夹或者项目

    步骤:File->Setting 打开设置面板,打开Directories节点,然后看到有Add Content Root 操作选项,单击弹出磁盘目录文件,选择对应项目或者目录即可.

  3. Chrome71版本使用screenfull.js全屏功能时报参数错误

    在生产环境长期使用的一个“全屏”功能突然失效了,查看Console 如下报错: Failed to execute 'requestFullscreen' on 'Element': paramete ...

  4. python中的MRO和C3算法

    一. 经典类和新式类 1.python多继承 在继承关系中,python子类自动用友父类中除了私有属性外的其他所有内容.python支持多继承.一个类可以拥有多个父类 2.python2和python ...

  5. 数据库访问接口(ODBC、OLE DB、ADO)

    最近在学C#的数据库编程,对于数据库接口技术这块的知识一直比较模糊,网上查了不少资料,看了几天还是朦朦胧胧的,只能做些笔记再研究了. 我们都知道,“数据库”是指一组相关信息的集合,最早的计算机应用之一 ...

  6. PHP 代码优化测试【Benchmark数据测试】

    由于经常被抓取文章内容,在此附上博客文章网址:,偶尔会更新某些出错的数据或文字,建议到我博客地址 :  --> 点击这里 Benchmark测试之前我们先来了解Benchmark.直接下载:ht ...

  7. [Objective-C语言教程]Posing(29)

    Posing,顾名思义,意思是“冒充”,它跟categories类似,但本质上不一样,Posing存在的目的在于子类可以冒充父类,使得后续的代码无需把父类修改为子类,就可以很方便的让父类表现成子类的行 ...

  8. Windows系统下如何在cmd命令窗口中切换Python2.7和Python3.6

    针对在同一系统下我们可能安装多个版本的Python,毕竟Python2.7与Python3.6还是有不同的需求,但是在用Cmd命令窗口是我们可能默认的系统变量环境是其中一个版本,当我们需要在cmd命令 ...

  9. forward与redirect

    前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址:后者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接.这样,从浏览器的地址栏中可以看到跳转后的链接地址.所以,前者 ...

  10. 第一个PSP0级

    1.计划: 需求描述: 按照图片要求设计添加新课程界面.(0.5分) 在后台数据库中建立相应的表结构存储课程信息.(0.5分) 实现新课程添加的功能. 要求判断任课教师为王建民.刘立嘉.刘丹.王辉.杨 ...