ASP.NET MVC 5 - ตัวตน วิธีรับ ApplicationUser ปัจจุบัน


237

ฉันมีนิติบุคคลบทความในโครงการของฉันที่มีคุณสมบัติชื่อApplicationUser Authorฉันจะรับวัตถุเต็มรูปแบบของการเข้าสู่ระบบในปัจจุบันได้ApplicationUserอย่างไร? ขณะที่การสร้างบทความใหม่ผมต้องตั้งค่าAuthorคุณสมบัติในการปัจจุบันArticleApplicationUser

ในกลไกการเป็นสมาชิกแบบเก่ามันเป็นเรื่องง่าย แต่ในวิธีการแบบผู้ถือหุ้นแบบใหม่ฉันไม่รู้ว่าจะทำอย่างไร

ฉันพยายามทำแบบนี้:

  • เพิ่มการใช้คำสั่งสำหรับส่วนขยายข้อมูลประจำตัว: using Microsoft.AspNet.Identity;
  • จากนั้นฉันพยายามรับผู้ใช้ปัจจุบัน: ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == User.Identity.GetUserId());

แต่ฉันได้รับข้อยกเว้นต่อไปนี้:

LINQ ไปยังเอนทิตีไม่รู้จักเมธอด 'System.String GetUserId (System.Security.Principal.IIdentity)' และวิธีนี้ไม่สามารถแปลเป็นนิพจน์ร้านค้าได้ แหล่งที่มา = EntityFramework

คำตอบ:


448

คุณไม่จำเป็นต้องค้นหาฐานข้อมูลโดยตรงสำหรับ ApplicationUser ปัจจุบัน

ที่แนะนำการพึ่งพาใหม่ของการมีบริบทพิเศษสำหรับ starters แต่ไปข้างหน้าตารางฐานข้อมูลผู้ใช้เปลี่ยน (3 ครั้งใน 2 ปีที่ผ่านมา) แต่ API มีความสอดคล้อง ตัวอย่างเช่นusersตารางเรียกว่าตอนนี้AspNetUsersในเอกลักษณ์กรอบและชื่อของหลายสาขาคีย์หลักที่เก็บรักษาไว้ที่เปลี่ยนแปลงดังนั้นรหัสในหลายคำตอบจะไม่ทำงานตามที่เป็น

ปัญหาอีกประการหนึ่งคือการเข้าถึง OWIN พื้นฐานไปยังฐานข้อมูลจะใช้บริบทแยกต่างหากดังนั้นการเปลี่ยนแปลงจากการเข้าถึง SQL แยกต่างหากสามารถสร้างผลลัพธ์ที่ไม่ถูกต้อง (เช่นไม่เห็นการเปลี่ยนแปลงที่เกิดขึ้นกับฐานข้อมูล) อีกครั้งแก้ปัญหาคือการทำงานร่วมกับ API การจัดหาและไม่พยายามที่จะทำงานรอบมัน

วิธีที่ถูกต้องในการเข้าถึงวัตถุผู้ใช้ปัจจุบันใน ASP.Net identity (ณ วันที่นี้) คือ:

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

หรือถ้าคุณมีการกระทำแบบอะซิงก์สิ่งที่ชอบ:

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

FindByIdต้องการให้คุณมีคำสั่งการใช้ดังต่อไปนี้เพื่อให้วิธีการที่ไม่ใช่ async UserManagerพร้อมใช้งาน (เป็นวิธีส่วนขยายสำหรับ UserManager ดังนั้นหากคุณไม่รวมสิ่งนี้คุณจะเห็นเท่านั้นFindByIdAsync):

using Microsoft.AspNet.Identity;

หากคุณไม่ได้อยู่ในคอนโทรลเลอร์เลย (เช่นคุณกำลังใช้การฉีด IOC) จากนั้นรหัสผู้ใช้จะถูกเรียกคืนจาก:

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

หากคุณไม่ได้อยู่ในตัวควบคุมบัญชีมาตรฐานคุณจะต้องเพิ่มสิ่งต่อไปนี้ (เป็นตัวอย่าง) ในตัวควบคุมของคุณ:

1. เพิ่มคุณสมบัติทั้งสองนี้:

    /// <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. เพิ่มสิ่งนี้ใน Constructor ของ Controller:

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

อัปเดตมีนาคม 2558

หมายเหตุ: การอัพเดตเฟรมเวิร์ก Identity ล่าสุดจะเปลี่ยนหนึ่งในคลาสพื้นฐานที่ใช้สำหรับการตรวจสอบความถูกต้อง ตอนนี้คุณสามารถเข้าถึงได้จากบริบท Owin ของ HttpContent ปัจจุบัน

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

ภาคผนวก:

เมื่อใช้ EF และ Identity Framework กับ Azure ผ่านการเชื่อมต่อฐานข้อมูลระยะไกล (เช่นการทดสอบโฮสต์ท้องถิ่นกับฐานข้อมูล Azure) คุณสามารถสุ่มเลือกข้อผิดพลาด“ ข้อผิดพลาดที่น่ากลัว: 19 - การเชื่อมต่อทางกายภาพไม่สามารถใช้งานได้” เนื่องจากสาเหตุถูกฝังอยู่ภายใน Identity Framework ซึ่งคุณไม่สามารถเพิ่มการลองใหม่ (หรือสิ่งที่ดูเหมือนจะหายไป.Include(x->someTable)) คุณจำเป็นต้องปรับใช้แบบกำหนดเองSqlAzureExecutionStrategyในโครงการของคุณ


5
@TBA - ขอบคุณฉันรู้ในภายหลังว่าเป็นวิธีการขยาย จำเป็นต้องเพิ่ม Microsoft.AspNet.Identity โดยใช้ ขอบคุณอีกครั้ง
Sentinel

2
ไม่พบประเภทหรือชื่อผู้ใช้ UserStore ฉันเพิ่มโดยใช้ Microsft.AspNet.Indentity
Wasfa

2
@Zapnologica: ดูเหมือนคำถามใหม่ (แนะนำให้คุณโพสต์) คุณสามารถขยายApplicationUserคลาส (เฉพาะแอปพลิเคชัน) และAspNetUsersตารางในแบบคู่ขนานและพวกเขาจะจัดเตรียมฟิลด์ใหม่ใด ๆ อีกครั้ง: อย่ากดฐานข้อมูลโดยตรง! :)
ไปที่เข้ารหัส

2
@ LifeH2O: ผู้ ApplicationUser กลับโดย FindById เป็นของคุณระดับสมบูรณ์ด้วยคุณคุณสมบัติพิเศษ โปรดลอง
Gone Coding

1
รอการหาวิธีแก้ปัญหาใหม่ของคุณ: P
Anup Sharma

60

ความผิดพลาดของฉันฉันไม่ควรใช้วิธีการในการสืบค้น LINQ

รหัสที่ถูกต้อง:

using Microsoft.AspNet.Identity;


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

2
User.Identiy.GetUserId ไม่มีอยู่สำหรับฉัน เป็นวิธีการที่ฉันกำหนดเอง? ฉันจะขึ้นอยู่กับผู้ใช้สิ่งสำคัญ
Gerrie Pretorius

9
ไม่เป็นไร ... คุณต้องการ "ใช้ Microsoft.AspNet.Identity;" สำหรับวิธีการที่จะมี
Gerrie Pretorius

4
แค่ทราบวัตถุผู้ใช้จะมองเห็นได้เฉพาะในตัวควบคุม
Miro J.

8
แน่นอนคุณควรใช้UserManagerวิธีการและไม่ตีฐานข้อมูลโดยตรงหรือไม่
Gone Coding

3
@Josh Bjelovuk: อย่ากดฐานข้อมูลโดยตรงเมื่อมี API ที่แนะนำการพึ่งพาใหม่ของการมีบริบทพิเศษสำหรับ starters แต่ไปข้างหน้าตารางฐานข้อมูลผู้ใช้เปลี่ยน (3 ครั้งใน 2 ปีที่ผ่านมา) แต่ API มีความสอดคล้อง
Gone Coding

33

มันอยู่ในความคิดเห็นของคำตอบ แต่ไม่มีใครได้โพสต์สิ่งนี้เป็นทางออกที่แท้จริง

คุณต้องเพิ่มคำสั่งการใช้ที่ด้านบน:

using Microsoft.AspNet.Identity;

2
ฉันมาที่นี่ด้วยข้อยกเว้นนั้นฉันแก้ไขมันด้วยสิ่งusingนั้น เห็นเป็น 15k คนได้เข้าชมคำถามที่ฉันคิดว่ามันเป็นคำตอบที่เป็นประโยชน์ :)
rtpHarry

2
@TrueBlueAussie แม้จะไม่ใช่คำตอบโดยตรงสำหรับคำถาม OPs แต่ฉันรู้สึกว่าการกล่าวถึงการใช้นั้นเป็นประโยชน์อย่างมาก
StuartQ

1
เพื่อความชัดเจนนั่นเป็นเพราะ.GetUserId()เป็นวิธีการขยาย
FSCKur

11

รหัสของ Ellbar ใช้งานได้! คุณต้องการเพิ่มโดยใช้เท่านั้น

1 - using Microsoft.AspNet.Identity;

และ ... รหัสของ Ellbar:

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

ด้วยรหัสนี้ (ในcurrentUser) คุณทำงานข้อมูลทั่วไปของผู้ใช้ที่เชื่อมต่อถ้าคุณต้องการข้อมูลเพิ่มเติม ... ดูลิงค์นี้


5
มันอาจ "ทำงาน" แต่ไม่แนะนำให้หลีกเลี่ยง API ที่ให้มาและกดฐานข้อมูลโดยตรงหากคุณใช้ API คุณไม่จำเป็นต้องทำงานพิเศษเพื่อรับข้อมูลเพิ่มเติมเนื่องจากมันจะอยู่ในApplicationUserวัตถุ
แล้ว

ฉันเห็นด้วย! อย่างไรก็ตามใช้วิธีนี้เพราะฉันมีระบบอยู่แล้วในวันนี้ด้วยการรันในฐานข้อมูลและฉันต้องการวิธีแก้ไขปัญหาอย่างง่ายเพื่อแก้ปัญหานี้! แน่นอนในระบบแรก ๆ ฉันจะวางวัตถุในคลาสและตัวตนที่เหมาะสม
Diego Borges

6

ในฐานะของ ASP.NET Identity 3.0.0 สิ่งนี้ได้รับการปรับสภาพใหม่

//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

สำหรับ MVC 5 เพียงมองเข้าไปในวิธีการเปิดใช้งาน EnableTwoFactorAuthentication ของ ManageController ในโครงร่างเทมเพลต WebApplication ซึ่งกำลังดำเนินการอยู่ที่นั่น:

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

คำตอบอยู่ตรงนั้นตามคำแนะนำของ Microsoft:

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

มันจะมีคุณสมบัติเพิ่มเติมทั้งหมดที่คุณกำหนดไว้ในคลาส ApplicationUser


5
ครอบคลุมแล้ว โปรดตรวจสอบว่าคำตอบที่เหมือนกันนั้นยังไม่ได้โพสต์ (หรือเพิ่มความคิดเห็นในคำตอบที่มีอยู่) :)
Gone Coding

3

ตอนนี้เทมเพลตโครงการ asp.mvc สร้างตัวควบคุมบัญชีที่ได้รับประโยชน์จากผู้ใช้ด้วยวิธีนี้:

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

งานต่อไปนี้สำหรับฉัน:

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

0

ฉันพร้อมที่จะรับผู้ใช้แอปพลิเคชันโดยทำตามส่วนของรหัสได้สำเร็จ

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

0

ในกรณีที่มีคนทำงานกับIdentityผู้ใช้ในweb formsฉันได้รับมันทำงานโดย:

var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindById(User.Identity.GetUserId());
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.