Vấn đề mã thông báo chống giả mạo (MVC 5)


122

Tôi đang gặp sự cố với mã thông báo chống giả mạo :( Tôi đã tạo lớp Người dùng của riêng mình, lớp này hoạt động tốt nhưng bây giờ tôi gặp lỗi bất cứ khi nào tôi truy cập trang / Tài khoản / Đăng ký . Lỗi là:

Khiếu nại loại ' http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier ' hoặc ' http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider ' là không có trên ClaimsIdentity đã cung cấp. Để bật hỗ trợ mã thông báo chống giả mạo với xác thực dựa trên xác nhận quyền sở hữu, vui lòng xác minh rằng nhà cung cấp xác nhận quyền sở hữu đã định cấu hình đang cung cấp cả hai xác nhận quyền sở hữu này trên các phiên bản ClaimsIdentity mà nó tạo. Nếu thay vào đó, nhà cung cấp xác nhận quyền sở hữu đã định cấu hình sử dụng một loại xác nhận quyền sở hữu khác làm mã nhận dạng duy nhất, thì nó có thể được định cấu hình bằng cách đặt thuộc tính tĩnh AntiForgeryConfig.UniqueClaimTypeIdentifier.

Tôi tìm thấy bài viết này:

http://stack247.wordpress.com/2013/02/22/antiforgerytoken-a-claim-of-type-nameidentifier-or-identityprovider-was-not-present-on-provided-claimsidentity/

vì vậy tôi đã thay đổi phương thức Application_Start của mình thành:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;
}

nhưng khi tôi làm điều đó, tôi gặp lỗi này:

Yêu cầu loại ' http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress ' không có trên ClaimsIdentity đã cung cấp.

Đa co ai đi ngang qua đây chưa? Nếu vậy bạn có biết cách giải quyết không?

Chúc mừng trước,
r3plica

Cập nhật 1

Đây là lớp người dùng tùy chỉnh của tôi:

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

Hồ sơ của tôi chỉ đơn giản cho các kho lưu trữ của tôi, trông giống như sau:

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

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

    string CredentialId { get; set; }
}

và lớp Người dùng là lớp Microsoft.AspNet.Identity.EntityFramework.User . AccountController của tôi trông giống như sau:

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

Nó từng được trang trí bằng thuộc tính [ValidateAntiForgeryToken] , nhưng đó là nơi nó ngừng hoạt động.

Tôi hy vọng đó là đủ mã :)


Bạn có thể chỉ cho chúng tôi lớp Người dùng tùy chỉnh và cách bạn sử dụng nó không?
LostInComputer

Tôi đã thêm lớp Người dùng tùy chỉnh, cùng với cách tôi đang sử dụng nó.
r3plica

Bạn đang sử dụng phiên bản beta. Tôi khuyên bạn nên nâng cấp lên phiên bản phát hành sau đó xem sự cố vẫn xảy ra.
LostInComputer

Câu trả lời:


230

Thử cài đặt (trong global.cs):

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

33
Tôi nghĩ điều quan trọng cần lưu ý là tại sao điều này hoạt động: Điều này yêu cầu AntiForgerylớp sử dụng NameIdentifier(là chuỗi id người dùng được tìm thấy bởi GetUserId). Cảm ơn câu trả lời của Mike Goodwin đã giúp tôi tìm hiểu điều này!
Matt DeKrey

Tôi đã thử "AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;" và gặp lỗi này "Chuỗi chứa nhiều hơn một phần tử phù hợp", trong trường hợp của tôi có một số xác nhận quyền sở hữu (tên, vai trò và địa chỉ email). Làm thế nào tôi có thể sắp xếp điều này?
Dhanuka777

9
Tôi đặt điều này trong Global.asax.cs
Mike Taverne

6
Đây cũng là giải pháp nếu bạn đang sử dụng OpenId (tức là Azure ActiveDirectory) làm authenticaiton của mình.
guysherman

6
Không gian tên đầy đủ .. Tôi đã phải đào một số để tìm ra nơi chứa ClaimTypes. System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier = System.Security.Claims.ClaimTypes.NameIdentifier;
Mark Rowe

65

Bạn có biết những gì bạn nhận được trong ClaimsIdentity của bạn? Nếu không:

  1. Xóa [ValidateAntiForgeryToken]thuộc tính
  2. Đặt một điểm ngắt ở đâu đó trong bộ điều khiển của bạn và ngắt ở đó
  3. Sau đó xem xét hiện tại ClaimsIdentityvà kiểm tra các yêu cầu
  4. Tìm một cái mà bạn nghĩ sẽ nhận dạng duy nhất người dùng của bạn
  5. Đặt thành AntiForgeryConfig.UniqueClaimTypeIdentifierloại xác nhận quyền sở hữu đó
  6. Đặt lại [ValidateAntiForgeryToken]thuộc tính

3
Không chỉ cung cấp câu trả lời cho thức ăn bằng thìa trực tiếp, câu trả lời này cho biết cơ sở và cho phép tự khám phá. :) Cảm ơn rất nhiều
NitinSingh 30/07/18

2
6. Đặt lại [ValidateAntiForgeryToken]thuộc tính
Scott Fraley

1
điều này thực sự đã giúp tôi. Hóa ra tôi đã nhận được một yêu cầu đối với một ứng dụng khác đang chạy trên máy chủ cục bộ của tôi, trong ứng dụng của tôi không có yêu cầu nào được sử dụng (đó là lý do tại sao điều khiếu nại nghe có vẻ kỳ lạ đối với tôi). Vì vậy, khi tôi đăng xuất khỏi ứng dụng khác, các xác nhận quyền sở hữu đã biến mất và lỗi cũng vậy. Trên môi trường thử nghiệm trực tiếp, các trang web này tách biệt hơn. Vì vậy, tôi nghĩ mình cần giải pháp nêu trên, nhưng chỉ để phát triển địa phương.
Michel

26

Chỉ cần đặt cái này vào global.asax.cs

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;

Cảm ơn. Điều tôi không hiểu là tại sao tôi phải thực hiện thay đổi này, tôi đã khắc phục một số vấn đề khác nhau mà tôi gặp phải với mã của mình vào đêm qua và mọi thứ đều hoạt động tốt. Không thay đổi bất cứ điều gì, tôi đã thử nghiệm điều này trên một máy khác và tất cả đều hoạt động cho đến vài phút trước.
Artorias2718,

14

Hãy thử mở liên kết trong cửa sổ ẩn danh hoặc xóa cookie khỏi miền đó (tức là localhost).


Tại sao điều này hoạt động và nguyên nhân của vấn đề là gì?
mok

Điều này hoạt động vì khi bạn có cookie phiên với mã định danh không hợp lệ, máy chủ sẽ cố gắng sử dụng mã định danh không hợp lệ mà không chuyển hướng người dùng đến trang đăng nhập và lấy mã định danh thích hợp.
rawel

3

Chỉnh sửa: Đã hiểu rõ hơn về vấn đề này tại thời điểm này, bạn có thể bỏ qua câu trả lời của tôi dưới đây.

Cài đặt AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;trong Application_Start () của Global.asax.cs đã sửa nó cho tôi. Mặc dù tôi đã http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifierđặt yêu cầu nhưng tôi vẫn gặp lỗi tương tự như trong câu hỏi ban đầu. Nhưng chỉ ra nó như trên bằng cách nào đó hoạt động.



Bắt đầu với MVC4, mã thông báo chống giả mạo không sử dụng User.Identity.Namelàm mã nhận dạng duy nhất. Thay vào đó, nó tìm kiếm hai yêu cầu được đưa ra trong thông báo lỗi.

Cập nhật LƯU Ý: Điều này không cần thiết Bạn có thể thêm các xác nhận quyền sở hữu còn thiếu vào ClaimsIdentity của mình khi người dùng đang đăng nhập, như sau:

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

Lưu ý rằng một trong các xác nhận quyền sở hữu có thể đã có từ trước đó và bạn sẽ gặp lỗi với các xác nhận quyền sở hữu trùng lặp nếu thêm cả hai. Nếu vậy, chỉ cần thêm một cái còn thiếu.


1
Tôi hiểu tại sao bạn đang sử dụng userId làm "/ nameidentifier", nhưng tại sao bạn lại đặt userId làm "/ IDprovider"?
AaronLS

2

Trong Global.asax.cs,

1.Thêm các không gian tên này

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

2.Thêm dòng này trong phương thức Application_Start:

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

Làm thế nào để nó bổ sung thêm bất kỳ giá trị hơn những người đã trả lời ở trên
NitinSingh

Cảm ơn vì đã thêm các sử dụng. @NitinSingh Tôi nghĩ rằng điều đó tăng thêm giá trị vì tôi không biết nên sử dụng không gian tên nào trong số ba không gian tên tiềm năng trong dự án của mình.
Keisha W

Bất cứ khi nào bạn thêm một chức năng mới, nó sẽ yêu cầu các tham chiếu chính xác. Một khi nó biên dịch, bạn nên loại bỏ những người không sử dụng thông qua menu Refactor trên click chuột phải
NitinSingh

0
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;

phù hợp với trường hợp của tôi, tôi đang sử dụng Xác thực ADFS.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.