ASP.NET MVC 5 - Danh tính. Cách tải xuống ApplicationUser hiện tại


237

Tôi có một thực thể Điều trong dự án của tôi có ApplicationUsertài sản được đặt tên Author. Làm thế nào tôi có thể nhận được đầy đủ các đối tượng hiện đang đăng nhập ApplicationUser? Trong khi tạo một bài viết mới, tôi phải đặt thuộc Authortính Articlethành hiện tại ApplicationUser.

Trong cơ chế Tư cách thành viên cũ, điều đó thật đơn giản, nhưng theo cách tiếp cận Danh tính mới, tôi không biết làm thế nào để làm điều này.

Tôi đã cố gắng làm theo cách này:

  • Thêm sử dụng câu lệnh cho tiện ích mở rộng Danh tính: using Microsoft.AspNet.Identity;
  • Sau đó, tôi cố gắng để có được người dùng hiện tại: ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == User.Identity.GetUserId());

Nhưng tôi nhận được ngoại lệ sau:

LINQ to Entities không nhận ra phương thức 'System.String GetUserId (System.Security.Principal.IIdentity)' và phương thức này có thể được dịch thành biểu thức lưu trữ. Nguồn = EntityFramework

Câu trả lời:


448

Bạn không cần phải truy vấn cơ sở dữ liệu trực tiếp cho ApplicationUser hiện tại.

Điều đó giới thiệu một sự phụ thuộc mới của việc có một bối cảnh bổ sung cho người mới bắt đầu, nhưng về phía trước các bảng cơ sở dữ liệu người dùng sẽ thay đổi (3 lần trong 2 năm qua) nhưng API là nhất quán. Ví dụ, usersbảng hiện được gọi AspNetUserstrong Khung nhận dạng và tên của một số trường khóa chính liên tục thay đổi, do đó, mã trong một số câu trả lời sẽ không còn hoạt động như hiện tại .

Một vấn đề khác là quyền truy cập OWIN cơ sở vào cơ sở dữ liệu sẽ sử dụng một ngữ cảnh riêng, do đó những thay đổi từ quyền truy cập SQL riêng biệt có thể tạo ra kết quả không hợp lệ (ví dụ: không thấy các thay đổi được thực hiện cho cơ sở dữ liệu). Một lần nữa, giải pháp là làm việc với API được cung cấp và không cố gắng làm việc xung quanh nó.

Cách chính xác để truy cập đối tượng người dùng hiện tại trong danh tính ASP.Net (tại thời điểm này) là:

var user = UserManager.FindById(User.Identity.GetUserId());

hoặc, nếu bạn có một hành động không đồng bộ, đại loại như:

var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

FindByIdyêu cầu bạn phải sử dụng câu lệnh sau để UserManagercó sẵn các phương thức không đồng bộ (chúng là các phương thức mở rộng cho UserManager, vì vậy nếu bạn không bao gồm điều này, bạn sẽ chỉ thấy FindByIdAsync):

using Microsoft.AspNet.Identity;

Nếu bạn hoàn toàn không ở trong bộ điều khiển (ví dụ: bạn đang sử dụng IOC tiêm), thì id người dùng được truy xuất đầy đủ từ:

System.Web.HttpContext.Current.User.Identity.GetUserId();

Nếu bạn không ở trong bộ điều khiển Tài khoản tiêu chuẩn, bạn sẽ cần thêm các mục sau (ví dụ) vào bộ điều khiển của mình:

1. Thêm hai thuộc tính này:

    /// <summary>
    /// Application DB context
    /// </summary>
    protected ApplicationDbContext ApplicationDbContext { get; set; }

    /// <summary>
    /// User manager - attached to application DB context
    /// </summary>
    protected UserManager<ApplicationUser> UserManager { get; set; }

2. Thêm phần này vào hàm tạo của Trình điều khiển:

    this.ApplicationDbContext = new ApplicationDbContext();
    this.UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(this.ApplicationDbContext));

Cập nhật tháng 3 năm 2015

Lưu ý: Bản cập nhật gần đây nhất cho khung Nhận dạng thay đổi một trong các lớp cơ bản được sử dụng để xác thực. Bây giờ bạn có thể truy cập nó từ Bối cảnh Owin của HttpContent hiện tại.

ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());

Phụ lục:

Khi sử dụng EF và Khung nhận dạng với Azure, qua kết nối cơ sở dữ liệu từ xa (ví dụ: kiểm tra máy chủ cục bộ vào cơ sở dữ liệu Azure), bạn có thể ngẫu nhiên gặp phải lỗi Lỗi đáng sợ: 19 - Kết nối vật lý không thể sử dụng được. Vì nguyên nhân được chôn giấu bên trong Khung nhận dạng, nơi bạn không thể thêm lần thử lại (hoặc có vẻ như bị thiếu .Include(x->someTable)), bạn cần thực hiện một tùy chỉnh SqlAzureExecutionStrategytrong dự án của mình.


5
@TBA - cảm ơn, tôi nhận ra sau đó là một phương thức mở rộng. Cần thêm Microsoft.AspNet.Identity bằng cách sử dụng. cảm ơn một lần nữa
Sentinel

2
Không thể tìm thấy loại hoặc tên người dùng. Không thể tìm thấy UserStore. Tôi đã thêm bằng
microsft.AspNet.Inentity

2
@Zapnologica: Nghe có vẻ như một câu hỏi mới (đề nghị bạn đăng nó). Bạn có thể mở rộng ApplicationUserlớp (ứng dụng cụ thể) và AspNetUsersbảng song song và họ sẽ cung cấp bất kỳ trường mới nào. Một lần nữa: Đừng đánh trực tiếp vào cơ sở dữ liệu! :)
Mã hóa đã qua

2
@ LifeH2O: ApplicationUser được FindById trả về là lớp của bạn , hoàn thành với các thuộc tính bổ sung của bạn . Hãy thử nó.
Mã hóa

1
Chờ đợi cách giải quyết mới của bạn: P
Anup Sharma

60

Lỗi của tôi, tôi không nên sử dụng một phương thức trong truy vấn LINQ.

Mã chính xác:

using Microsoft.AspNet.Identity;


string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);

2
User.Identiy.GetUserId không tồn tại đối với tôi. đó là tôi tùy chỉnh phương pháp? Tôi chỉ nhận được tới User.Identity
Gerrie Pretorius

9
Không bao giờ ... bạn cần "sử dụng Microsoft.AspNet.Identity;" cho phương pháp đó ở đó
Gerrie Pretorius

4
Chỉ cần một lưu ý, đối tượng Người dùng chỉ hiển thị trong Bộ điều khiển.
Miro J.

8
Chắc chắn bạn nên sử dụng UserManagercác phương thức và không đánh trực tiếp vào cơ sở dữ liệu?
Mã hóa

3
@Josh Bjelovuk: Không bao giờ đánh trực tiếp vào cơ sở dữ liệu khi có sẵn API. Điều đó giới thiệu một sự phụ thuộc mới của việc có một bối cảnh bổ sung cho người mới bắt đầu, nhưng về phía trước các bảng cơ sở dữ liệu người dùng sẽ thay đổi (3 lần trong 2 năm qua) nhưng API là nhất quán.
Mã hóa đã qua

33

Trong các bình luận của câu trả lời nhưng không ai đăng bài này là giải pháp thực tế.

Bạn chỉ cần thêm một câu lệnh sử dụng ở trên cùng:

using Microsoft.AspNet.Identity;

2
Tôi đến đây với ngoại lệ đó, tôi đã giải quyết nó bằng điều đó using. Thấy 15k mọi người đã truy cập câu hỏi tôi đoán đó là một câu trả lời hữu ích :)
rtpHarry

2
@TrueBlueAussie, mặc dù không phải là câu trả lời trực tiếp cho câu hỏi của OP, tôi cảm thấy việc đề cập đến việc sử dụng là một bổ sung rất hữu ích.
StuartQ

1
Để rõ ràng, đó là vì đây .GetUserId()là một phương thức mở rộng
FSCKur

11

Mã của Ellbar hoạt động! Bạn chỉ cần thêm bằng cách sử dụng.

1 - using Microsoft.AspNet.Identity;

Và ... mã của Ellbar:

2 - string currentUserId = User.Identity.GetUserId(); ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);

Với mã này (in currentUser), bạn làm việc với dữ liệu chung của người dùng được kết nối, nếu bạn muốn có thêm dữ liệu ... hãy xem liên kết này


5
Nó có thể "hoạt động", nhưng chắc chắn không nên bỏ qua API được cung cấp và truy cập trực tiếp vào cơ sở dữ liệu Nếu bạn đã sử dụng API, bạn sẽ không cần làm thêm để có được dữ liệu bổ sung như đã có trong ApplicationUserđối tượng
Mã hóa đã qua

Tôi đồng ý! Tuy nhiên, đã dùng đến cách này vì tôi đã có sẵn một hệ thống, với cơ sở dữ liệu và tôi cần một giải pháp đơn giản để giải quyết vấn đề này! Chắc chắn, trong một hệ thống ban đầu, tôi sẽ đặt các đối tượng vào các lớp và danh tính thích hợp của chúng.
Diego Borges

6

Kể từ ASP.NET Identity 3.0.0, Điều này đã được tái cấu trúc thành

//returns the userid claim value if present, otherwise returns null
User.GetUserId();

6
ApplicationDbContext context = new ApplicationDbContext();
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
ApplicationUser currentUser = UserManager.FindById(User.Identity.GetUserId());

string ID = currentUser.Id;
string Email = currentUser.Email;
string Username = currentUser.UserName;

3

Đối với MVC 5, chỉ cần nhìn vào bên trong phương thức EnableTwoFactorAuthentication của ManageContoder trong mẫu giàn giáo WebApplication, nó đang được thực hiện ở đó:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> EnableTwoFactorAuthentication()
        {
            await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
            var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
            if (user != null)
            {
                await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
            }
            return RedirectToAction("Index", "Manage");
        }

Câu trả lời là có ngay theo đề xuất của chính Microsoft:

var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

Nó sẽ có tất cả các thuộc tính bổ sung mà bạn đã xác định trong lớp ApplicationUser.


5
Đã được bảo hiểm. Vui lòng kiểm tra xem câu trả lời giống hệt chưa được đăng (hoặc thêm nhận xét vào câu trả lời hiện có) :)
Mã hóa

3

Ngay bây giờ, mẫu dự án asp.mvc tạo ra một bộ điều khiển tài khoản có được người sử dụng theo cách này:

HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>()

Các công việc sau đây cho tôi:

ApplicationUser user = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(User.Identity.GetUserId());

0

Tôi đã có sẵn thành công để có được Người dùng ứng dụng bằng cách theo dõi đoạn mã

var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            var user = manager.FindById(User.Identity.GetUserId());
            ApplicationUser EmpUser = user;

0

Trong trường hợp ai đó đang làm việc với Identityngười dùng web forms, tôi đã làm cho nó hoạt động bằng cách làm như vậy:

var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindById(User.Identity.GetUserId());
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.