C# 防伪令牌问题 (MVC 5)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19977833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Anti-forgery token issue (MVC 5)
提问by r3plica
I am having an issue with the anti-forgery token :( I have created my own User class which worked fine but now I am getting an error whenever I go to the /Account/Registerpage. The error is:
我的防伪令牌有问题 :( 我创建了自己的 User 类,该类工作正常,但现在每当我转到/Account/Register页面时都会收到错误消息。错误是:
A claim of type 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier' or 'http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider' was not present on the provided ClaimsIdentity. To enable anti-forgery token support with claims-based authentication, please verify that the configured claims provider is providing both of these claims on the ClaimsIdentity instances it generates. If the configured claims provider instead uses a different claim type as a unique identifier, it can be configured by setting the static property AntiForgeryConfig.UniqueClaimTypeIdentifier.
类型为“ http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier”或“ http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider”的声明是不存在于提供的 ClaimsIdentity 中。要通过基于声明的身份验证启用防伪令牌支持,请验证配置的声明提供程序是否在它生成的 ClaimsIdentity 实例上提供这两个声明。如果配置的声明提供程序使用不同的声明类型作为唯一标识符,则可以通过设置静态属性 AntiForgeryConfig.UniqueClaimTypeIdentifier 进行配置。
I found this article:
我找到了这篇文章:
so I changed my Application_Startmethod to this:
所以我将我的Application_Start方法更改为:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;
}
but when I do that, I get this error:
但是当我这样做时,我收到此错误:
A claim of type 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress' was not present on the provided ClaimsIdentity.
提供的 ClaimsIdentity 中不存在类型为“ http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress”的声明。
Has anyone come across this before? If so, do you know how to solve it?
有没有人遇到过这个?如果是这样,您知道如何解决吗?
Cheers in advance,
r3plica
提前干杯,
r3plica
Update 1
更新 1
Here is my custom user class:
这是我的自定义用户类:
public class Profile : User, IProfile
{
public Profile()
: base()
{
this.LastLoginDate = DateTime.UtcNow;
this.DateCreated = DateTime.UtcNow;
}
public Profile(string userName)
: base(userName)
{
this.CreatedBy = this.Id;
this.LastLoginDate = DateTime.UtcNow;
this.DateCreated = DateTime.UtcNow;
this.IsApproved = true;
}
[NotMapped]
public HttpPostedFileBase File { get; set; }
[Required]
public string CompanyId { get; set; }
[Required]
public string CreatedBy { get; set; }
public string ModifiedBy { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public DateTime LastLoginDate { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredTitle")]
public string Title { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredFirstName")]
public string Forename { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredLastName")]
public string Surname { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredEmail")]
public string Email { get; set; }
public string JobTitle { get; set; }
public string Telephone { get; set; }
public string Mobile { get; set; }
public string Photo { get; set; }
public string LinkedIn { get; set; }
public string Twitter { get; set; }
public string Facebook { get; set; }
public string Google { get; set; }
public string Bio { get; set; }
public string CompanyName { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredCredentialId")]
public string CredentialId { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredSecurityCode")]
public bool IsLockedOut { get; set; }
public bool IsApproved { get; set; }
[Display(Name = "Can only edit own assets")]
public bool CanEditOwn { get; set; }
[Display(Name = "Can edit assets")]
public bool CanEdit { get; set; }
[Display(Name = "Can download assets")]
public bool CanDownload { get; set; }
[Display(Name = "Require approval to upload assets")]
public bool RequiresApproval { get; set; }
[Display(Name = "Can approve assets")]
public bool CanApprove { get; set; }
[Display(Name = "Can synchronise assets")]
public bool CanSync { get; set; }
public bool AgreedTerms { get; set; }
public bool Deleted { get; set; }
}
public class ProfileContext : IdentityStoreContext
{
public ProfileContext(DbContext db)
: base(db)
{
this.Users = new UserStore<Profile>(this.DbContext);
}
}
public class ProfileDbContext : IdentityDbContext<Profile, UserClaim, UserSecret, UserLogin, Role, UserRole>
{
}
I profile is just simple for my repositories, looks like this:
对于我的存储库,我的配置文件很简单,如下所示:
public interface IProfile
{
string Id { get; set; }
string CompanyId { get; set; }
string UserName { get; set; }
string Email { get; set; }
string CredentialId { get; set; }
}
and the Userclass is the Microsoft.AspNet.Identity.EntityFramework.Userclass. My AccountControllerlooks like this:
而User类是Microsoft.AspNet.Identity.EntityFramework.User类。我的AccountController看起来像这样:
[Authorize]
public class AccountController : Controller
{
public IdentityStoreManager IdentityStore { get; private set; }
public IdentityAuthenticationManager AuthenticationManager { get; private set; }
public AccountController()
{
this.IdentityStore = new IdentityStoreManager(new ProfileContext(new ProfileDbContext()));
this.AuthenticationManager = new IdentityAuthenticationManager(this.IdentityStore);
}
//
// GET: /Account/Register
[AllowAnonymous]
public ActionResult Register()
{
return View();
}
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
try
{
// Create a profile, password, and link the local login before signing in the user
var companyId = Guid.NewGuid().ToString();
var user = new Profile(model.UserName)
{
CompanyId = companyId,
Title = model.Title,
Forename = model.Forename,
Surname = model.Surname,
Email = model.Email,
CompanyName = model.CompanyName,
CredentialId = model.CredentialId
};
if (await IdentityStore.CreateLocalUser(user, model.Password))
{
//Create our company
var company = new Skipstone.Web.Models.Company()
{
Id = companyId,
CreatedBy = user.Id,
ModifiedBy = user.Id,
Name = model.CompanyName
};
using (var service = new CompanyService())
{
service.Save(company);
}
await AuthenticationManager.SignIn(HttpContext, user.Id, isPersistent: false);
return RedirectToAction("Setup", new { id = companyId });
}
else
{
ModelState.AddModelError("", "Failed to register user name: " + model.UserName);
}
}
catch (IdentityException e)
{
ModelState.AddModelError("", e.Message);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// POST: /Account/Setup
public ActionResult Setup(string id)
{
var userId = User.Identity.GetUserId();
using (var service = new CompanyService())
{
var company = service.Get(id);
var profile = new Profile()
{
Id = userId,
CompanyId = id
};
service.Setup(profile);
return View(company);
}
}
}
It used to be decorated with the [ValidateAntiForgeryToken]attribute, but that is where it stopped working.
它曾经使用[ValidateAntiForgeryToken]属性进行修饰,但这就是它停止工作的地方。
I hope that is enough code :)
我希望这是足够的代码:)
采纳答案by Alex Filipovici
Try setting (in global.cs):
尝试设置(在 global.cs 中):
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
回答by Mike Goodwin
Do you know what claims you do get in your ClaimsIdentity? If not:
您知道您在 ClaimsIdentity 中得到了哪些索赔吗?如果不:
- Remove the
[ValidateAntiForgeryToken]
attribute - Put a breakpoint somewhere in your controller and break at it
- Then look at the current
ClaimsIdentity
and examine the claims - Find one that you think will uniquely identify your user
- Set the
AntiForgeryConfig.UniqueClaimTypeIdentifier
to that claim type - Put back the
[ValidateAntiForgeryToken]
attribute
- 移除
[ValidateAntiForgeryToken]
属性 - 在控制器中的某个地方放置一个断点并在它处中断
- 然后查看电流
ClaimsIdentity
并检查索赔 - 找到一个您认为可以唯一标识您的用户的人
- 将 设置
AntiForgeryConfig.UniqueClaimTypeIdentifier
为该声明类型 - 放回
[ValidateAntiForgeryToken]
属性
回答by Gurgen Sargsyan
Try open link in incognito window or clear cookie from that domain(i.e. localhost).
尝试在隐身窗口中打开链接或清除该域(即本地主机)中的 cookie。
回答by cederlof
Edit: Having a greater understanding of this problem at this moment, you can disregard my answer below.
编辑:此时对这个问题有了更深入的了解,您可以忽略我在下面的回答。
Setting AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
in Application_Start() of Global.asax.cs fixed it for me. Even though I have the claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
set, I get the same error as in the original question. But pointing it out as above somehow works.
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
Global.asax.cs 的 Application_Start() 中的设置为我修复了它。即使我http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
设置了声明,我也会遇到与原始问题相同的错误。但是如上所述指出它以某种方式起作用。
Starting with MVC4 the anti-forgery-token doesn't use User.Identity.Name
as the unique identifier. Instead it looks for the two claims given in the error message.
从 MVC4 开始,防伪令牌不用User.Identity.Name
作唯一标识符。相反,它会查找错误消息中给出的两个声明。
Update NOTE: This should not be neededYou can add the missing claims to your ClaimsIdentity when the user is being logged in, like so:
更新注意:这应该不需要您可以在用户登录时将缺少的声明添加到您的 ClaimsIdentity,如下所示:
string userId = TODO;
var identity = System.Web.HttpContext.Current.User.Identity as ClaimsIdentity;
identity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", userId));
identity.AddClaim(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", userId));
Note that one of the claims might already be there from before, and you will get an error with duplicate claims if you add both. If so, just add the one missing.
请注意,其中一个声明可能已经存在,如果您添加两个声明,您将收到重复声明的错误。如果是这样,只需添加缺少的一项。
回答by mzk
Just put this in global.asax.cs
把它放在 global.asax.cs
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;
回答by Kiran Chaudhari
In Global.asax.cs,
在 Global.asax.cs 中,
1.Add these namespaces
1.添加这些命名空间
using System.Web.Helpers;
using System.Security.Claims;
2.Add this line in method Application_Start:
2.在方法Application_Start中添加这一行:
protected void Application_Start()
{
.......
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;
}
回答by Ashu
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;
works for my case i am using ADFS Authentication.
适用于我的情况,我正在使用 ADFS 身份验证。