Jak utworzyć tożsamość użytkownika na podstawie zasad oświadczeń [duplikat]

Nov 24 2020

Używam asp.net mvc z uwierzytelnianiem kont służbowych / szkolnych. Obecnie próbuję zaimplementować tożsamość do procesu użytkownika.

Oto moja ApplicationUserklasa:

public class ApplicationUser: IdentityUser
{
    public ICollection<Semester> Semesters { get; set; }
}

Jak dotąd tożsamość działa dobrze, jest tylko jeden problem. Kiedy loguję się do aplikacji za pomocą mojego konta szkolnego, mogę zadzwonić tak ClaimsPrincipalsjak Userw kontrolerach. Aby uzyskać prąd ApplicationUser, możesz użyć UserManager( await _userManager.GetUserAsync(User), Userbędąc ClaimsPrincipals) Ale ponieważ nie zapisałem mojego konta szkolnego w bazie danych, wynik będzie zerowy. Jeśli utworzę nowy, ApplicationUsertaki jak poniżej

var newUser = new ApplicationUser()
{
    UserName = User.Identity.Name,
    Email = User.Identity.Name
};
await _userManager.CreateAsync(newUser);
await _userManager.AddClaimsAsync(newUser, User.Claims);

Spowoduje to pomyślne utworzenie i zapisanie nowego użytkownika w bazie danych z oświadczeniami. Ale wtedy, gdy spróbuję uzyskać nowy utworzony ApplicationUserz await _userManager.GetUserAsync(User)wynikiem, nadal będzie zerowy. Jeśli DbContextuzyskam dostęp do mojego i otrzymam wszystko ApplicationUsers, nowo utworzony ApplicationUserjest tam. Jak więc mogę utworzyć na ApplicationUserpodstawie ClaimsPrincipalsloginu otrzymanego z mojego konta szkolnego?

Odpowiedzi

Ogglas Dec 07 2020 at 19:49

Kredyty dla @poke za to.

UserManager.GetUserAsyncwewnętrznie używa UserManager.GetUserIddo pobrania identyfikatora użytkownika, który jest następnie używany do odpytywania obiektu z magazynu użytkownika (tj. z bazy danych).

GetUserId w zasadzie wygląda tak:

public string GetUserId(ClaimsPrincipal principal)
{
    return principal.FindFirstValue(Options.ClaimsIdentity.UserIdClaimType);
}

Więc to zwraca wartość roszczenia Options.ClaimsIdentity.UserIdClaimType. Optionsto IdentityOptionsobiekt , z którym konfigurujesz tożsamość. Domyślnie wartość UserIdClaimTypeto ClaimTypes.NameIdentifier, tj "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier".

Więc kiedy próbujesz użyć UserManager.GetUserAsync(HttpContext.User), gdy ta jednostka główna użytkownika ma UserIDroszczenie, menedżer użytkowników po prostu szuka innego roszczenia.

Możesz to naprawić, przełączając się na ClaimTypes.NameIdentifier:

new ClaimsIdentity(new[]
{
    new Claim(ClaimTypes.Name, user.UserName),
    new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
})

Możesz też odpowiednio skonfigurować tożsamość, aby używała Twojego UserIDtypu oświadczenia:

// in Startup.ConfigureServices
services.AddIdentity(options => {
    options.ClaimIdentity.UserIdClaimType = "UserID";
});

Źródło:

https://stackoverflow.com/a/51122850/3850405

MattE. Dec 04 2020 at 05:55

Oświadczenia od zewnętrznego dostawcy będą specyficzne dla tego dostawcy. Nie loguje się do lokalnego magazynu tożsamości w Twojej aplikacji, po prostu twierdzi, że wie, kim jest użytkownik. Musisz więc zalogować użytkownika do swojego sklepu (SignInManager), zanim będziesz mógł go użyć do autoryzacji. Jeśli nie zależy Ci na ochronie zasobów i po prostu chcesz poznać użytkownika, możesz bezpośrednio zamapować się na swój wewnętrzny sklep

Oświadczenia w nagłówku muszą zostać przechwycone przez „oprogramowanie pośredniczące” ASPNET przy użyciu dostawcy uwierzytelniania, który następnie ustawi obiekt użytkownika w HttpContext. Gdy już masz użytkownika, musisz zmapować swój lokalny sklep użytkowników na te z konta szkolnego, a następnie uzyskać roszczenia jako oddzielne wywołanie od wyniku. Zazwyczaj wiadomość e-mail jest tematem roszczenia i może być używana do mapowania:

    var userName = User.Identity.Name;
    var user = _userManager.FindByNameAsync(userName);
    var claims = _userManager.GetClaimsAsync(user);