首页 文章

防伪令牌问题(MVC 5)

提问于
浏览
104

我遇到了防伪令牌的问题:(我已经创建了自己的User类,但工作正常,但现在每次进入 /Account/Register 页面时都会收到错误 . 错误是:

“http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier”或“http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider”类型的声明未提供的ClaimsIdentity . 要使用基于声明的身份验证启用防伪令牌支持,请验证配置的声明提供程序是否在其生成的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”类型的声明 .

有没有人遇到过这个?如果是这样,你知道如何解决它吗?

提前干杯,
r3plica

Update 1

这是我的自定义用户类:

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>
{
}

我的配置文件对我的存储库来说很简单,看起来像这样:

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

它曾经使用 [ValidateAntiForgeryToken] 属性进行修饰,但这就是它停止工作的地方 .

我希望这是足够的代码:)

7 回答

  • 20

    尝试设置(在global.cs中):

    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
    
  • 2

    你知道你在ClaimsIdentity中得到的主张吗?如果不:

    • 删除 [ValidateAntiForgeryToken] 属性

    • 在控制器的某处放置一个断点并打破它

    • 然后查看当前的 ClaimsIdentity 并检查索赔

    • 找到您认为将唯一标识您的用户的一个

    • AntiForgeryConfig.UniqueClaimTypeIdentifier 设置为该声明类型

  • 0

    把它放在global.asax.cs中

    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;
    
  • 0

    尝试在隐身窗口中打开链接或清除该域中的cookie(即localhost) .

  • 49

    编辑:此时对这个问题有了更深入的了解,你可以忽略我的答案 .

    在Global.asax.cs的Application_Start()中设置 AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier; 为我修复了它 . 即使我设置了声明 http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier ,我也会遇到与原始问题相同的错误 . 但是如上所述指出它可行 .



    从MVC4开始,防伪令牌不使用 User.Identity.Name 作为唯一标识符 . 相反,它会查找错误消息中给出的两个声明 .

    Update NOTE: This should not be needed 您可以在用户登录时将缺少的声明添加到您的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));
    

    请注意,其中一个声明可能已经存在,如果您同时添加两个声明,则会出现重复声明的错误 . 如果是这样,只需添加一个缺失的 .

  • 196

    在Global.asax.cs中,

    1.添加这些名称空间

    using System.Web.Helpers;
    using System.Security.Claims;
    

    2.在方法Application_Start中添加以下行:

    protected void Application_Start()
     {
           .......
           AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;
     }
    
  • 12

    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;

    适用于我的情况我正在使用ADFS身份验证 .

相关问题