Jak utworzyć tożsamość użytkownika na podstawie zasad oświadczeń [duplikat]
Używam asp.net mvc z uwierzytelnianiem kont służbowych / szkolnych. Obecnie próbuję zaimplementować tożsamość do procesu użytkownika.
Oto moja ApplicationUser
klasa:
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 ClaimsPrincipals
jak User
w kontrolerach. Aby uzyskać prąd ApplicationUser
, możesz użyć UserManager
( await _userManager.GetUserAsync(User)
, User
będąc ClaimsPrincipals
) Ale ponieważ nie zapisałem mojego konta szkolnego w bazie danych, wynik będzie zerowy. Jeśli utworzę nowy, ApplicationUser
taki 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 ApplicationUser
z await _userManager.GetUserAsync(User)
wynikiem, nadal będzie zerowy. Jeśli DbContext
uzyskam dostęp do mojego i otrzymam wszystko ApplicationUsers
, nowo utworzony ApplicationUser
jest tam. Jak więc mogę utworzyć na ApplicationUser
podstawie ClaimsPrincipals
loginu otrzymanego z mojego konta szkolnego?
Odpowiedzi
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
. Options
to IdentityOptionsobiekt , z którym konfigurujesz tożsamość. Domyślnie wartość UserIdClaimType
to 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 UserID
roszczenie, 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 UserID
typu oświadczenia:
// in Startup.ConfigureServices
services.AddIdentity(options => {
options.ClaimIdentity.UserIdClaimType = "UserID";
});
Źródło:
https://stackoverflow.com/a/51122850/3850405
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);