ruf*_*fin 0 c# ajax antiforgerytoken asp.net-web-api asp.net-core-2.0
当我无法保证客户端将使用哪个平台时,我[Authorize]在严格(即View较少)的ASP.NET Core WebAPI项目中使用注释时遇到了问题.也就是说,应用程序需要是一个真正的API,不需要特定的平台来访问.
注意:当我说"严格的WebAPI"时,我的项目实际上是作为由...生成的MVC项目开始的.
Run Code Online (Sandbox Code Playgroud)dotnet new mvc --auth Individual...我立即从中删除了所有视图等,并更改了路由首选项以匹配WebAPI约定.
当我通过AJAX访问标准登录功能(在下面的粘贴中剥离到基本要素)时,我获得了一个JSON有效负载并返回了一个cookie.
[HttpPost("apiTest")]
[AllowAnonymous]
public async Task<IActionResult> ApiLoginTest([FromBody] LoginViewModel model, string returnUrl = null)
{
object ret = new { Error = "Generic Error" };
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
ret = new { Success = true };
else
ret = new { Error = "Invalid login attempt" };
}
return new ObjectResult(ret);
}
Run Code Online (Sandbox Code Playgroud)
成功时,返回类似于以下内容的cookie:
.AspNetCore.Identity.Application=CfDJ8Ge9E-[many characters removed]; path=/; domain=localhost; HttpOnly; Expires=Fri, 16 Mar 2018 16:27:47 GMT;
Run Code Online (Sandbox Code Playgroud)
在看似成功登录后,我尝试访问两个完全相同的API端点,一个注释AllowAnonymous,一个Authorized:
private IActionResult _getStatus()
{
object ret = new { Error = "Generic Error" };
var isSignedIn = _signInManager.IsSignedIn(User);
var userName = _userManager.GetUserName(User);
return new ObjectResult(
new {
SignedIn = isSignedIn,
Name = userName
}
);
}
[HttpGet("authorizedTest")]
[Authorize]
public IActionResult GetCurrentLoginInfo2()
{
return _getStatus();
}
[HttpGet("anonymousTest")]
[AllowAnonymous]
public IActionResult GetCurrentLoginInfo()
{
return _getStatus();
}
Run Code Online (Sandbox Code Playgroud)
该anonymousTest端点是登录前后访问,但它告诉我,我不能登录.(SignedIn是false)甚至登录后.该authorizedTest端点是永远不可访问.
我的猜测是单个cookie不足以通过[Authorized]标签.我相信我还需要一个防伪值,要么是由默认情况下发送@Html.AntiForgeryToken()的第二个cookie 生成的表单中的隐藏值View.那饼干看起来像这样......
.AspNetCore.Antiforgery.0g4CU0eoNew=CfDJ8Ge9E-[many characters removed]; path=/; domain=localhost; HttpOnly; Expires=Tue, 19 Jan 2038 03:14:07 GMT;
Run Code Online (Sandbox Code Playgroud)
我已经看到很多关于如何使用纯AJAX的答案,基本上说" 从隐藏的形式获得防伪 "或" 从标题中读取它 ",但我没有View; 没有隐藏的形式.我也不想真正想要为客户提供部分观点.
我见过的最好的答案是这个谈论使用iOS.情况似乎是类似的:
因为我们不向客户提供HTML
@Html.AntiForgeryToken(),所以我们不能使用该标准,因此我们必须使用AntiForgery.GetTokens这些标记获取并将令牌分发给我们的客户.
但即使我的Intellisense"看到" AntiForgery.GetTokens,它也无法编译,即使在抓住了似乎正确的nuget包之后:
dotnet add package microsoft-web-helpers --version 2.1.20710.2
Run Code Online (Sandbox Code Playgroud)
那么我的问题是:如何在Razor之外使用Antiforgery ,但使用ASP.NET Core创建一个受Identity限制的WebAPI风格的项目?
有一段时间,我无法弄清楚为什么我的代码在严格的WebAPI项目中不起作用,但是在移植到标准身份ASP.NET Core项目(从中创建一个dotnet new mvc --auth Individual)时就做了AccountController.
钥匙?options.LoginPath.当我在WebAPI的土地上时,我转发到API端点登录:
options.LoginPath = "/api/accounts/requestLogin";
在库存项目中,它View默认为 a ,它在加载时提供防伪cookie:
options.LoginPath = "/Account/Login"; // As soon as Login.cshtml loads, BAM. .AspNetCore.Antiforgery cookie.
奇怪的是,有时我可以删除AspNetCore.AntiforgeryPostman中的第二个cookie,但仍然可以访问一个[Authorize]注释方法,所以我不是百分百肯定我不是在这里咆哮错误的树,但这是我迄今为止最好的领导......
首先,请求是幂等的:每个请求都是唯一的,必须包含服务请求所需的所有信息,包括授权.传统网站使用基于cookie的身份验证,并且Web浏览器一致地将所有cookie发送回服务器,无需用户干预.随请求一起发送的cookie用于授权请求,给出用户经过身份验证的外观,而无需不断传递用户名和密码.
API是一种不同的野兽.由于它通常不是发出请求的实际Web浏览器,因此添加授权是一种手动操作.这通常通过Authorization请求标头处理,其中包括诸如承载标记之类的东西.如果你没有通过你的请求传递这样的东西,那么它就像用户从未进行过身份验证一样,因为实际上他们没有进行身份验证.服务器不能唯一地标识特定请求来自何处,并且不知道或不关心特定客户端之前发出请求.HTTP协议按设计分散.
其次,防伪代币是完全不同的东西.它们旨在防止XSRF攻击,其中恶意网站可能会尝试从您的网站托管表单的副本以捕获信息,但随后发布到您的网站,以便用户不知道发生了任何事情.例如,假设我设置了一个站点http://faceboook.com(注意额外的o).大多数用户不会注意到链接中的这种细微差别,甚至可能会在地址栏中意外地将其自行键入.然后,我的恶意网站会创建一个真正的Facebook主页的副本,并有一个登录的地方.用户将他们的Facebook登录凭据输入我的表单(我稍后会使用它来窃取他们的帐户),但我会将这些凭据发布到真实Facebook网站使用的同一个处理程序.最终结果是用户最终在Facebook,登录,并继续他们发布猫视频等业务.但是,现在我有他们的登录凭据.
防伪代币可以防止这种情况发生.令牌已加密,因此我无法在恶意网站上创建能够在Facebook端成功验证的令牌.验证失败时,请求被拒绝.基于存在要解决的防伪令牌的问题,它们大多与API不兼容,因为通常API 旨在由第三方使用.受防伪令牌保护的任何API端点都无法被该应用或域外部的任何内容使用.无论如何,它们与请求的身份验证/授权无关.
| 归档时间: |
|
| 查看次数: |
1522 次 |
| 最近记录: |