反伪造令牌问题

9 浏览
0 Comments

反伪造令牌问题

我在使用防伪令牌时遇到了问题 🙁 我已经创建了自己的用户类,一切正常,但是当我访问/Account/Register页面时,出现了错误。错误信息如下:

提供的ClaimsIdentity中未提供类型为'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier'或'http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider'的声明。要启用基于声明的认证的防伪令牌支持,请验证配置的声明提供程序是否在生成的ClaimsIdentity实例上提供了这两个声明。如果配置的声明提供程序使用不同的声明类型作为唯一标识符,则可以通过设置静态属性AntiForgeryConfig.UniqueClaimTypeIdentifier来进行配置。

我找到了这篇文章:http://stack247.wordpress.com/2013/02/22/antiforgerytoken-a-claim-of-type-nameidentifier-or-identityprovider-was-not-present-on-provided-claimsidentity/,所以我将我的Application_Start方法修改为:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;
}

但是这样做后,我又遇到了这个错误:

提供的ClaimsIdentity中未提供类型为'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'的声明。

有人遇到过这个问题吗?如果有,你知道如何解决吗?


这是我的自定义用户类:

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(this.DbContext);
    }
}
public class ProfileDbContext : IdentityDbContext
{
}

我的IProfile接口只是简单地用于我的存储库,如下所示:

public interface IProfile
{
    string Id { get; set; }
    string CompanyId { get; set; }
    string UserName { get; set; }
    string Email { get; set; }
    string CredentialId { get; set; }
}

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 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);
        }
    }
}

它以前使用[ValidateAntiForgeryToken]属性进行了修饰,但在这里停止工作。为什么?

0
0 Comments

Anti-forgery token issues(防伪令牌问题)是由于以下原因导致的:

1. 在global.asax.cs文件中没有设置AntiForgeryConfig的UniqueClaimTypeIdentifier属性。

解决方法是,在global.asax.cs文件中添加以下代码:

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;

这段代码会将UniqueClaimTypeIdentifier属性设置为ClaimsIdentity的DefaultNameClaimType值。

感谢。我不明白的是为什么我必须做这个更改,昨晚我修复了一些我代码中的不同问题,一切都正常工作。在不修改任何内容的情况下,我在另一台机器上进行了测试,一切都正常,直到几分钟前。

0
0 Comments

在解决(Anti-forgery token issues)这个问题时,可以尝试在global.cs文件中设置以下代码:

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

这个设置告诉AntiForgery类使用NameIdentifier作为唯一的声明类型标识符,通过GetUserId方法获取到的用户id字符串。感谢Mike Goodwin的回答,帮助我理解了这一点。

当我尝试设置AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;时,出现了错误"Sequence contains more than one matching element"。在我的情况下,有几个声明(name、role和emailaddress)。我该如何解决这个问题呢?

我在Global.asax.cs文件中进行了以下设置。

如果你使用OpenId(例如Azure ActiveDirectory)作为身份验证方式,这也是解决方案。

完整的命名空间...我必须仔细查找才能找到ClaimTypes所在的位置。System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier = System.Security.Claims.ClaimTypes.NameIdentifier;

这个设置位于System.Web.WebPages.dll版本2.0.0.0中,所以不要忘记将该引用添加到项目中。

0
0 Comments

问题出现的原因是在ClaimsIdentity中获取到的声明不正确,解决方法是通过以下步骤进行调试和设置:

1. 移除控制器中的`[ValidateAntiForgeryToken]`属性。

2. 在控制器中的某个位置设置断点并停在那里。

3. 查看当前的ClaimsIdentity并检查其中的声明。

4. 找到一个你认为能唯一标识用户的声明。

5. 将`AntiForgeryConfig.UniqueClaimTypeIdentifier`设置为该声明的类型。

6. 将`[ValidateAntiForgeryToken]`属性重新加回控制器中。

这个方法不仅仅提供了直接的解决方案,还能帮助你了解背景知识并进行自我发现。非常感谢这个答案,它对我非常有帮助。事实证明,在我的应用程序中,我获取了另一个在本地主机上运行的应用程序的声明,而在我的应用程序中没有使用声明(这就是为什么声明的东西对我来说听起来很奇怪)。因此,当我登出另一个应用程序时,声明消失了,错误也消失了。在实时测试环境中,这些站点更分离。所以我认为我需要上述解决方案,但只用于本地开发。在我的情况下,我正在将一个现有的应用程序转换为使用IdentityServer,并且出现了这个错误。使用Mike的方法,我能够检查声明并使用适当的声明,比如主题id(sub声明)。

0