Проблема с анти-подделкой (MVC 5)

У меня проблема с токеном анти-подделки:( Я создал свой собственный класс 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;
}

но когда я это сделаю, я получаю эту ошибку:

Требование типа 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress' не присутствовал на предоставленном ClaimsIdentity.

Кто-нибудь сталкивался с этим раньше? Если да, знаете ли вы, как его решить?

Приветствия заранее,
r3plica

Обновление 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>
{
}

I профиль просто для моих репозиториев, выглядит так:

public interface IProfile
{
    string Id { get; set; }
    string CompanyId { get; set; }

    string UserName { get; set; }
    string Email { get; set; }

    string CredentialId { get; set; }
}

а класс Пользователь - класс 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], но там он переставал работать.

Надеюсь, этого достаточно кода:)

Ответ 1

Попробуйте установить (в global.cs):

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

Ответ 2

Знаете ли вы, какие претензии вы получаете в своей заявке? Если нет:

  1. Удалите атрибут [ValidateAntiForgeryToken]
  2. Поместите точку останова где-нибудь в свой контроллер и сломайте ее
  3. Затем посмотрите на текущий ClaimsIdentity и изучите требования
  4. Найдите того, кто, по вашему мнению, будет уникально идентифицировать вашего пользователя
  5. Установите AntiForgeryConfig.UniqueClaimTypeIdentifier для этого типа заявки
  6. Верните атрибут [ValidateAntiForgeryToken]

Ответ 3

Просто поместите это в global.asax.cs

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;

Ответ 4

Попробуйте открыть ссылку в окне инкогнито или очистить cookie из этого домена (то есть localhost).

Ответ 5

Изменить: имея более глубокое понимание этой проблемы в данный момент, вы можете игнорировать мой ответ ниже.

Настройка AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier; в Application_Start() Global.asax.cs исправила его для меня. Хотя у меня есть требование http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier set, я получаю ту же ошибку, что и в исходном вопросе. Но указание на это, как описано выше, как-то работает.



Начиная с MVC4, токен анти-подделки не использует User.Identity.Name как уникальный идентификатор. Вместо этого он ищет две претензии, приведенные в сообщении об ошибке.

Обновление ПРИМЕЧАНИЕ. Это не требуется. Вы можете добавить недостающие утверждения в свой 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));

Обратите внимание, что одна из претензий может уже существовать раньше, и вы получите ошибку с дублирующимися утверждениями, если вы добавите оба. Если да, просто добавьте отсутствующий.

Ответ 6

В Global.asax.cs,

1. Добавьте эти пространства имен

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

2. Добавьте эту строку в метод Application_Start:

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

Ответ 7

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;

работает для моего случая я использую аутентификацию ADFS.