我正在尝试编写一些简单的测试代码,验证基本身份验证机制下的用户身份验证。如何从标头(header)中检索到凭证?
string authorizationHeader = this.HttpContext.Request.Headers["Authorization"];
我现在该怎么办?有很多教程,但我对.NET和身份验证都很陌生,你能在回答中详细解释每一个步骤的目的和原因吗?
我正在尝试编写一些简单的测试代码,验证基本身份验证机制下的用户身份验证。如何从标头(header)中检索到凭证?
string authorizationHeader = this.HttpContext.Request.Headers["Authorization"];
我现在该怎么办?有很多教程,但我对.NET和身份验证都很陌生,你能在回答中详细解释每一个步骤的目的和原因吗?
来自我的博客:
这将详细解释所有工作原理:
每当您使用基本认证时,都会向HTTP请求添加一个头,它看起来类似于:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
来源:http://en.wikipedia.org/wiki/Basic_access_authentication
"QWxhZGRpbjpvcGVuIHNlc2FtZQ=="只是以Base64编码的"用户名:密码"(http://en.wikipedia.org/wiki/Base64)。为了访问.NET(C#)中的标头和其他HTTP属性,您需要访问当前的Http上下文:
HttpContext httpContext = HttpContext.Current;
您可以在System.Web命名空间中找到此内容。
授权标头不是HttpContext中唯一的标头。为了访问标头,我们需要从请求中获取它。
string authHeader = this.httpContext.Request.Headers["Authorization"];
(或者您可以使用 AuthenticationHeaderValue.TryParse,如下面的 pasx的答案中所建议的)
如果您调试代码,您会看到该标头的内容类似于:
Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
您已经提取了标头,现在有几件事情需要做:
就像这样:
if (authHeader != null && authHeader.StartsWith("Basic")) {
//Extract credentials
} else {
//Handle what happens if that isn't the case
throw new Exception("The authorization header is either empty or isn't Basic.");
}
现在,您可以尝试获取用户名和密码的值。首先,您需要摆脱 "Basic " 子字符串。您可以这样做:
string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
请查看以下链接以获取更多详细信息:
现在我们需要将Base64解码为字符串:
//the coding should be iso or you could use ASCII and UTF-8 decoder
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));
username:password
为了获取用户名和密码,我们可以简单地获取“:”的索引。
int seperatorIndex = usernamePassword.IndexOf(':');
username = usernamePassword.Substring(0, seperatorIndex);
password = usernamePassword.Substring(seperatorIndex + 1);
最终的代码可能如下所示:
HttpContext httpContext = HttpContext.Current;
string authHeader = this.httpContext.Request.Headers["Authorization"];
if (authHeader != null && authHeader.StartsWith("Basic")) {
string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));
int seperatorIndex = usernamePassword.IndexOf(':');
var username = usernamePassword.Substring(0, seperatorIndex);
var password = usernamePassword.Substring(seperatorIndex + 1);
} else {
//Handle what happens if that isn't the case
throw new Exception("The authorization header is either empty or isn't Basic.");
}
除了主要答案,摆脱“Basic”子字符串的最佳方法是使用AuthenticationHeaderValue Class:
var header = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentials = header.Parameter;
如果标头内容无效,例如:"Basic"部分不存在,则会抛出FormatException异常。
或者,如果您不想引发异常,请使用AuthenticationHeaderValue.TryParse。
来自@DawidO的精彩回答。
如果你只是想提取基本身份验证凭据,并依靠.NET魔法,假设你有HttpContext,那么这也可以工作:
public static void StartListener() {
using (var hl = new HttpListener()) {
hl.Prefixes.Add("http://+:8008/");
hl.AuthenticationSchemes = AuthenticationSchemes.Basic;
hl.Start();
Console.WriteLine("Listening...");
while (true) {
var hlc = hl.GetContext();
var hlbi = (HttpListenerBasicIdentity)hlc.User.Identity;
Console.WriteLine(hlbi.Name);
Console.WriteLine(hlbi.Password);
//TODO: validater user
//TODO: take action
}
}
}
记住,使用字符串可能不太安全。它们会一直存储在内存中,直到被垃圾回收器清除。
IndexOf
应该选择字符的第一个出现位置。因此,根据 RFC 7617 明确指出“另外,包含冒号字符的用户ID是无效的,因为用户密码字符串中的第一个冒号分隔了用户ID和密码”,所以您的用户名不能包含冒号。 - Dawid O