ASP.NET vNext Kestrel + windows 身份验证
ASP.NET vNext Kestrel + windows authentication
我在 linux 系统上安装了一个 ASP.NET 网络应用程序,运行良好,我可以浏览所有内容。现在我想知道,是否有可能或解决方法将 windows 身份验证方案与 Kestrel 服务器一起使用?正如我在 google 上搜索后看到的那样,目前不支持此功能。
感谢您的回答。
编辑:
但是 windows 身份验证在 Kestrel 中不起作用,我能够通过在我的 webb 应用程序中实施 NTLM 身份验证的质询-响应协议来获取用户名。
基于https://loune.net/2009/09/ntlm-authentication-in-php-now-with-ntlmv2-hash-checking/
在 Windows 上,IIS/ASP.NET 依靠 Windows API 来执行 Windows 身份验证。 Linux 上不存在这样的 API,因此 Kestrel 将不支持 Windows 身份验证,除非有一天 Microsoft 工程师填补空白。
好的,我接受,windows 身份验证在 Linux 中不可用,但是在我的问题中使用 link 我们可以编写一个自定义的 ActionFilterAttribute,这使得 NTLM 身份验证进程:
public async override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = (ControllerBase)filterContext.Controller;
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (!(await IsAuthorized(filterContext.HttpContext, controller)))
{
filterContext.Result = new HttpStatusCodeResult(401);
}
}
else
{
//TODO check access rights
}
}
private async Task<bool> IsAuthorized(HttpContext context, ControllerBase controller)
{
if (!context.Request.Headers.ContainsKey("Authorization"))
{
context.Response.Headers.Add("WWW-Authenticate", "NTLM");
return false;
}
var header = context.Request.Headers["Authorization"][0].Substring(5);
var message = System.Text.Encoding.ASCII.GetString(
Convert.FromBase64String(header));
if (!message.StartsWith("NTLMSSP"))
{
return false;
}
//type 1 message received
if (message[8] == '\x01')
{
byte[] type2Message =
{
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,//Signature
0x02, 0x00, 0x00, 0x00, //Type 2 Indicator
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Security Buffer
0x01, 0x02, 0x81, 0x00, //Flags
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Challenge
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Context
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 //Target info
};
context.Response.Headers.Add("WWW-Authenticate", "NTLM "
+ Convert.ToBase64String(type2Message));
return false;
}
//type 3 message received
else if (message[8] == '\x03')
{
var userName = GetMessageString(message, 36);
var domainName = GetMessageString(message, 28);
var workstation = GetMessageString(message, 44);
var user = controller.DbContext.Users.FirstOrDefault(
u => u.WindowsAccount.ToLower() == userName.ToLower());
if (user != null)
{
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.Name, userName));
context.User.AddIdentity(identity);
try
{
await controller.SignInManager.SignInAsync(user, false);
}
catch { }
return true;
}
}
return false;
}
private string GetMessageString(string message, int start, bool unicode = true)
{
var length = message[start + 1] * 256 + message[start];
var offset = message[start + 5] * 256 + message[start + 4];
if (unicode)
return message.Substring(offset, length).Replace("[=10=]", "");
else
return message.Substring(offset, length);
}
我在 linux 系统上安装了一个 ASP.NET 网络应用程序,运行良好,我可以浏览所有内容。现在我想知道,是否有可能或解决方法将 windows 身份验证方案与 Kestrel 服务器一起使用?正如我在 google 上搜索后看到的那样,目前不支持此功能。
感谢您的回答。
编辑:
但是 windows 身份验证在 Kestrel 中不起作用,我能够通过在我的 webb 应用程序中实施 NTLM 身份验证的质询-响应协议来获取用户名。
基于https://loune.net/2009/09/ntlm-authentication-in-php-now-with-ntlmv2-hash-checking/
在 Windows 上,IIS/ASP.NET 依靠 Windows API 来执行 Windows 身份验证。 Linux 上不存在这样的 API,因此 Kestrel 将不支持 Windows 身份验证,除非有一天 Microsoft 工程师填补空白。
好的,我接受,windows 身份验证在 Linux 中不可用,但是在我的问题中使用 link 我们可以编写一个自定义的 ActionFilterAttribute,这使得 NTLM 身份验证进程:
public async override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = (ControllerBase)filterContext.Controller;
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (!(await IsAuthorized(filterContext.HttpContext, controller)))
{
filterContext.Result = new HttpStatusCodeResult(401);
}
}
else
{
//TODO check access rights
}
}
private async Task<bool> IsAuthorized(HttpContext context, ControllerBase controller)
{
if (!context.Request.Headers.ContainsKey("Authorization"))
{
context.Response.Headers.Add("WWW-Authenticate", "NTLM");
return false;
}
var header = context.Request.Headers["Authorization"][0].Substring(5);
var message = System.Text.Encoding.ASCII.GetString(
Convert.FromBase64String(header));
if (!message.StartsWith("NTLMSSP"))
{
return false;
}
//type 1 message received
if (message[8] == '\x01')
{
byte[] type2Message =
{
0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00,//Signature
0x02, 0x00, 0x00, 0x00, //Type 2 Indicator
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Security Buffer
0x01, 0x02, 0x81, 0x00, //Flags
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Challenge
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Context
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 //Target info
};
context.Response.Headers.Add("WWW-Authenticate", "NTLM "
+ Convert.ToBase64String(type2Message));
return false;
}
//type 3 message received
else if (message[8] == '\x03')
{
var userName = GetMessageString(message, 36);
var domainName = GetMessageString(message, 28);
var workstation = GetMessageString(message, 44);
var user = controller.DbContext.Users.FirstOrDefault(
u => u.WindowsAccount.ToLower() == userName.ToLower());
if (user != null)
{
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.Name, userName));
context.User.AddIdentity(identity);
try
{
await controller.SignInManager.SignInAsync(user, false);
}
catch { }
return true;
}
}
return false;
}
private string GetMessageString(string message, int start, bool unicode = true)
{
var length = message[start + 1] * 256 + message[start];
var offset = message[start + 5] * 256 + message[start + 4];
if (unicode)
return message.Substring(offset, length).Replace("[=10=]", "");
else
return message.Substring(offset, length);
}