Jak uzyskać bieżący identyfikator zalogowanego użytkownika w ASP.NET Core

179

Zrobiłem to już wcześniej przy użyciu MVC5, User.Identity.GetUserId()ale wydaje się, że tutaj nie działa. Nie User.Identityma GetUserId()metody

ja używam Microsoft.AspNet.Identity

MRainzo
źródło
2
spróbować tego System.Web.HttpContext.Current.User.Identity.Name?
Pravin Deshmukh
Dziękuję @PravinDeshmukh, ale to zwraca nazwę użytkownika, a nie identyfikator
MRainzo
1
Powinno działać. Zobacz przykłady w asp.net github.com/aspnet/Identity/blob/… . Tylko upewnij się, że użytkownik jest zalogowany. @PravinDeshmukh, nigdy nie używaj System.Web.HttpContext.Current w vnext :)
user960567
1
Cześć @ user960567, czy możesz nam powiedzieć, dlaczego?
Pravin Deshmukh
@PravinDeshmukh, ponieważ nie będzie działać na .NET core i nie ma zależności System.Web.
user960567

Odpowiedzi:

148

Aktualizacja w wersji ASP.NET Core> = 2,0

W kontrolerze:

public class YourControllerNameController : Controller
{
    private readonly UserManager<ApplicationUser> _userManager;

    public YourControllerNameController(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }

    public async Task<IActionResult> YourMethodName()
    {
        var userId =  User.FindFirstValue(ClaimTypes.NameIdentifier) // will give the user's userId
        var userName =  User.FindFirstValue(ClaimTypes.Name) // will give the user's userName

        ApplicationUser applicationUser = await _userManager.GetUserAsync(User);
        string userEmail = applicationUser?.Email; // will give the user's Email
    }
}

W innej klasie:

public class OtherClass
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    public OtherClass(IHttpContextAccessor httpContextAccessor)
    {
       _httpContextAccessor = httpContextAccessor;
    }

   public void YourMethodName()
   {
      var userId = _httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
   }
}

Następnie należy zarejestrować się IHttpContextAccessorna Startupzajęcia w następujący sposób:

public void ConfigureServices(IServiceCollection services)
{
    services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

    // Or you can also register as follows

    services.AddHttpContextAccessor();
}

Aby uzyskać większą czytelność metod rozszerzenia zapisu w następujący sposób:

public static class ClaimsPrincipalExtensions
{
    public static T GetLoggedInUserId<T>(this ClaimsPrincipal principal)
    {
        if (principal == null)
            throw new ArgumentNullException(nameof(principal));

        var loggedInUserId = principal.FindFirstValue(ClaimTypes.NameIdentifier);

        if (typeof(T) == typeof(string))
        {
            return (T)Convert.ChangeType(loggedInUserId, typeof(T));
        }
        else if (typeof(T) == typeof(int) || typeof(T) == typeof(long))
        {
            return loggedInUserId != null ? (T)Convert.ChangeType(loggedInUserId, typeof(T)) : (T)Convert.ChangeType(0, typeof(T));
        }
        else
        {
            throw new Exception("Invalid type provided");
        }
    }

    public static string GetLoggedInUserName(this ClaimsPrincipal principal)
    {
        if (principal == null)
            throw new ArgumentNullException(nameof(principal));

        return principal.FindFirstValue(ClaimTypes.Name);
    }

    public static string GetLoggedInUserEmail(this ClaimsPrincipal principal)
    {
        if (principal == null)
            throw new ArgumentNullException(nameof(principal));

        return principal.FindFirstValue(ClaimTypes.Email);
    }
}

Następnie użyj w następujący sposób:

public class YourControllerNameController : Controller
{
    public IActionResult YourMethodName()
    {
        var userId = User.GetLoggedInUserId<string>(); // Specify the type of your UserId;
        var userName = User.GetLoggedInUserName();
        var userEmail = User.GetLoggedInUserEmail();
    }
}

public class OtherClass
{
     private readonly IHttpContextAccessor _httpContextAccessor;
     public OtherClass(IHttpContextAccessor httpContextAccessor)
     {
         _httpContextAccessor = httpContextAccessor;
     }

     public void YourMethodName()
     {
         var userId = _httpContextAccessor.HttpContext.User.GetLoggedInUserId<string>(); // Specify the type of your UserId;
     }
}
TanvirArjel
źródło
1
Ale w moim przypadku Użytkownik zwraca wartość null? Gdzie ja robię źle?
Sruthi Varghese,
Czy na pewno jesteś zalogowany jako użytkownik?
TanvirArjel
Mój scenariusz jest taki, jak chcę, aby nazwa użytkownika zalogowała się do mojego systemu. Niech to będzie Ubuntu czy Windows? A ponieważ testuję to w systemie Windows, jestem zalogowany pod swoim nazwiskiem. Ale wraca null.
Sruthi Varghese,
Następnie musisz zobaczyć swój kod! Może to być dowolny agent zewnętrzny odgrywający tutaj rolę.
TanvirArjel
2
Zauważyłem, że jeśli masz wynik zerowy z User.Identity.Name, może to być spowodowane włączeniem uwierzytelniania anonimowego. Mogłem User.Identity.Nameodzyskać moją domenę i nazwę użytkownika, rozwijając Properties > launchSettings.json, ustawiając anonymousAuthenticationna falsei windowsAuthenticationdo true.
Andrew Gray
109

Do ASP.NET Core 1.0 RC1 :

To User.GetUserId () z przestrzeni nazw System.Security.Claims .

Od ASP.NET Core 1.0 RC2 :

Teraz musisz użyć UserManager . Możesz utworzyć metodę, aby pobrać bieżącego użytkownika:

private Task<ApplicationUser> GetCurrentUserAsync() => _userManager.GetUserAsync(HttpContext.User);

I uzyskaj informacje o użytkowniku z obiektem:

var user = await GetCurrentUserAsync();

var userId = user?.Id;
string mail = user?.Email;

Uwaga: Możesz to zrobić bez używania metody pisania pojedynczych wierszy, jak ta string mail = (await _userManager.GetUserAsync(HttpContext.User))?.Email, ale nie jest to zgodne z zasadą pojedynczej odpowiedzialności. Lepiej wyodrębnić sposób, w jaki zdobywasz użytkownika, ponieważ jeśli pewnego dnia zdecydujesz się zmienić system zarządzania użytkownikami, na przykład użyć innego rozwiązania niż tożsamość, będzie to bolesne, ponieważ będziesz musiał przejrzeć cały kod.

AdrienTorris
źródło
1
Mam przestrzeń nazw System.Security.Claims i zestaw Microsoft.AspNet.Identity.
scottheckel,
2
Myślę, że ta odpowiedź jest lepsza niż akceptowana odpowiedź, zwłaszcza że rdzeń asp.net promuje wstrzykiwanie zależności.
Phillip Davis
2
Wydaje się to niewłaściwe, ponieważ userManager wysyła żądanie do bazy danych w celu pobrania informacji o użytkowniku. I w tym przypadku userId był już dostępny w HttpContext.User
incognito
@incognito Identyfikator był tylko przykładem, ale wszystkie potrzebne informacje można uzyskać za pomocą obiektu użytkownika
AdrienTorris
2
@Adrien, ale pytanie brzmiało, jak uzyskać identyfikator użytkownika. Chciałem tylko powiedzieć, że podany sposób nie jest najbardziej wydajny. W tym przypadku wolałbym odpowiedź Sorena lub krótszą wersję, którą można znaleźć w komentarzach.
incognito
91

możesz go pobrać w swoim kontrolerze:

using System.Security.Claims;
var userId = this.User.FindFirstValue(ClaimTypes.NameIdentifier);

lub napisz metodę rozszerzającą, taką jak poprzednio .Core v1.0

using System;
using System.Security.Claims;

namespace Shared.Web.MvcExtensions
{
    public static class ClaimsPrincipalExtensions
    {
        public static string GetUserId(this ClaimsPrincipal principal)
        {
            if (principal == null)
                throw new ArgumentNullException(nameof(principal));

            return principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        }
    }
}

i uzyskaj wszędzie tam, gdzie jest dostępny User ClaimsPrincipal :

using Microsoft.AspNetCore.Mvc;
using Shared.Web.MvcExtensions;

namespace Web.Site.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return Content(this.User.GetUserId());
        }
    }
}
Soren
źródło
16
Krótsza wersja:var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
CFreitas
1
Zauważ, że ta metoda rozszerzenia działa tylko dla użytkownika wewnątrz kontrolerów, a nie dla komponentów widoku, ponieważ komponent widoku User jest z
IPrincipal
@AK możesz użyć, Convert.ToInt32(User.FindFirstValue(ClaimTypes.NameIdentifier))aby uzyskać całkowity identyfikator użytkownika
Hamza Khanzada
1
@HamzaKhanzada Tak, to działa, ale wygląda tak długo i brzydko.
AK
39

Uwzględniłem użycie System.Security.Claims i mogłem uzyskać dostęp do metody rozszerzenia GetUserId ()

Uwaga: już korzystałem z Microsoft.AspNet.Identity, ale nie mogłem uzyskać metody rozszerzenia. Więc myślę, że oba z nich muszą być używane w połączeniu ze sobą

using Microsoft.AspNet.Identity;
using System.Security.Claims;

EDYCJA : Ta odpowiedź jest teraz nieaktualna. Spójrz na odpowiedź Sorena lub Adriena, aby znaleźć przestarzały sposób osiągnięcia tego w CORE 1.0

MRainzo
źródło
17
To był tajny sos, ale dla każdego, kto spojrzy po dodaniu tych zastosowań, jest ... var userId = User.GetUserId();
Samurai Ken
4
Rozszerzenie .GetUserId () z ClaimsPrincipal (Controller.User) zostało przeniesione do => UserManager.GetUserId (User);
Soren
1
using System.Security.Claims; var userId = this.User.FindFirst (ClaimTypes.NameIdentifier);
Przełącz się
3
Kciuki w górę za poprzednio ważną odpowiedź i poprawne zidentyfikowanie nowej „poprawnej” odpowiedzi.
pimbrouwers,
26

Tylko dla .NET Core 2.0 Poniższe są wymagane do pobrania identyfikatora użytkownika zalogowanego użytkownika w Controllerklasie:

var userId = this.User.FindFirstValue(ClaimTypes.NameIdentifier);

lub

var userId = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);

na przykład

contact.OwnerID = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
Człowiek wyroczni
źródło
17

Jak stwierdzono gdzieś w tym poście, metoda GetUserId () została przeniesiona do UserManager.

private readonly UserManager<ApplicationUser> _userManager;

public YourController(UserManager<ApplicationUser> userManager)
{
    _userManager = userManager;
}

public IActionResult MyAction()
{
    var userId = _userManager.GetUserId(HttpContext.User);

    var model = GetSomeModelByUserId(userId);

    return View(model);
}

Jeśli uruchomiłeś pusty projekt, może być konieczne dodanie Menedżera użytkownika do usług w startup.cs. W przeciwnym razie powinno to już mieć miejsce.

Menno Guldemond
źródło
10

musisz zaimportować Microsoft.AspNetCore.Identity & System.Security.Claims

// to get current user ID
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);

// to get current user info
var user = await _userManager.FindByIdAsync(userId);
Mansur Haider
źródło
z tego wszystkiego wynika, że ​​Twój jest jedynym, który współpracuje z ASP.NET CORE v 2.0. Congratz!
Just Fair
to jest to. Każdy z .NET Core 2.0 i nowszych, oto twoja odpowiedź
alvinchesaro,
1
Przetestowano na platformie .NET Core 3.1 w ustawieniu interfejsu API sieci Web + JWT. Chcę, aby aktualnie zalogowany użytkownik znajdował się w kontrolerze podstawowym, nie jest to wydajne, wysyłanie zapytań do użytkownika z bazy danych dla każdego żądania itp. Czy istnieje sposób na uzyskanie bieżącego użytkownika bez wysyłania zapytań do bazy danych?
Nexus
dlaczego mój wraca "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"po User.FindFirstValue(ClaimTypes.NameIdentifier);?
dziecinny
5

Chociaż odpowiedź Adriena jest poprawna, możesz to wszystko zrobić w jednej linii. Nie ma potrzeby korzystania z dodatkowej funkcji ani bałaganu.

Działa Sprawdziłem to w ASP.NET Core 1.0

var user = await _userManager.GetUserAsync(HttpContext.User);

wtedy możesz uzyskać inne właściwości zmiennej, takie jak user.Email. Mam nadzieję, że to komuś pomoże.

Ahmad
źródło
3
Powodem, dla którego używam metody, jest przestrzeganie zasady pojedynczej odpowiedzialności. Jeśli nie wyodrębnisz sposobu, w jaki zdobywasz użytkownika, będzie to bolesne, jeśli pewnego dnia zdecydujesz się zmodyfikować swój system zarządzania użytkownikami, na przykład użyć innego rozwiązania niż tożsamość.
AdrienTorris
5

W przypadku interfejsu API ASP.NET Core 2.0, Entity Framework Core 2.0, AspNetCore.Identity 2.0 ( https://github.com/kkagill/ContosoUniversity-Backend ):

IdZostała zmieniona naUser.Identity.Name

    [Authorize, HttpGet("Profile")]
    public async Task<IActionResult> GetProfile()
    {
        var user = await _userManager.FindByIdAsync(User.Identity.Name);

        return Json(new
        {
            IsAuthenticated = User.Identity.IsAuthenticated,
            Id = User.Identity.Name,
            Name = $"{user.FirstName} {user.LastName}",
            Type = User.Identity.AuthenticationType,
        });
    }

Odpowiedź:

wprowadź opis obrazu tutaj

jv_
źródło
this.User.Identity.NameJednak na podstawie mojego testu jest to nazwa użytkownika. W moim teście nazwa użytkownika to e-mail, czy użytkownik loguje się z rejestracji, czy loguje się z zewnętrznego loginu (np. Facebook, Google). Poniższy kod zwraca userId. Używam automatycznie zwiększanego klucza podstawowego dla mojej tabeli użytkowników tożsamości, stąd int.Parse. int userId = int.Parse(this.User.FindFirstValue(ClaimTypes.NameIdentifier));
Michael Buen
1
FindByIdAsyncnie działa, ponieważ podajesz nazwę użytkownika. Działa, gdy zastąpisz go FindByNameAsync.
Jasper
4

w APiController

User.FindFirst(ClaimTypes.NameIdentifier).Value

Coś takiego otrzymasz roszczenia

Usman
źródło
1

User.Identity.GetUserId ();

nie istnieje w rdzeniu tożsamości asp.net 2.0. w tym zakresie poradziłem sobie w inny sposób. stworzyłem wspólną klasę do wykorzystania w całej aplikacji, ze względu na uzyskiwanie informacji o użytkowniku.

utwórz wspólną klasę PCommon i interfejs IPCommon, dodając odniesienieusing System.Security.Claims

using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace Common.Web.Helper
{
    public class PCommon: IPCommon
    {
        private readonly IHttpContextAccessor _context;
        public PayraCommon(IHttpContextAccessor context)
        {
            _context = context;
        }
        public int GetUserId()
        {
            return Convert.ToInt16(_context.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier));
        }
        public string GetUserName()
        {
            return _context.HttpContext.User.Identity.Name;
        }

    }
    public interface IPCommon
    {
        int GetUserId();
        string GetUserName();        
    }    
}

Tutaj implementacja wspólnej klasy

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Logging;
using Pay.DataManager.Concreate;
using Pay.DataManager.Helper;
using Pay.DataManager.Models;
using Pay.Web.Helper;
using Pay.Web.Models.GeneralViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Pay.Controllers
{

    [Authorize]
    public class BankController : Controller
    {

        private readonly IUnitOfWork _unitOfWork;
        private readonly ILogger _logger;
        private readonly IPCommon _iPCommon;


        public BankController(IUnitOfWork unitOfWork, IPCommon IPCommon, ILogger logger = null)
        {
            _unitOfWork = unitOfWork;
            _iPCommon = IPCommon;
            if (logger != null) { _logger = logger; }
        }


        public ActionResult Create()
        {
            BankViewModel _bank = new BankViewModel();
            CountryLoad(_bank);
            return View();
        }

        [HttpPost, ActionName("Create")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Insert(BankViewModel bankVM)
        {

            if (!ModelState.IsValid)
            {
                CountryLoad(bankVM);
                //TempData["show-message"] = Notification.Show(CommonMessage.RequiredFieldError("bank"), "Warning", type: ToastType.Warning);
                return View(bankVM);
            }


            try
            {
                bankVM.EntryBy = _iPCommon.GetUserId();
                var userName = _iPCommon.GetUserName()();
                //_unitOfWork.BankRepo.Add(ModelAdapter.ModelMap(new Bank(), bankVM));
                //_unitOfWork.Save();
               // TempData["show-message"] = Notification.Show(CommonMessage.SaveMessage(), "Success", type: ToastType.Success);
            }
            catch (Exception ex)
            {
               // TempData["show-message"] = Notification.Show(CommonMessage.SaveErrorMessage("bank"), "Error", type: ToastType.Error);
            }
            return RedirectToAction(nameof(Index));
        }



    }
}

get userId i name w akcji insert

_iPCommon.GetUserId();

Dzięki, Maksud

Maksud
źródło
1
Czy musisz zarejestrować IHttpContextAccessor w Startup.cs?
REMESQ
1
Nie REMESQ, nie wstrzyknąłem tego do uruchamiania, ale działam w mojej aplikacji
Maksud
1

Aby uzyskać bieżący identyfikator użytkownika w widokach maszynki do golenia, możemy wstrzyknąć UserManager w widoku w następujący sposób:

@inject Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> _userManager
@{ string userId = _userManager.GetUserId(User); }

Mam nadzieję, że uznasz to za przydatne.

HO3EiN
źródło
0

używać można użyć

string userid = User.FindFirst("id").Value;

z jakiegoś powodu NameIdentifier pobiera teraz nazwę użytkownika (.net core 2.2)

Mosta
źródło
0

Jako administrator pracujący na profilach innych osób i potrzebujesz uzyskać identyfikator profilu, nad którym pracujesz, możesz użyć ViewBag do przechwycenia Id, np. ViewBag.UserId = userId; while userId jest ciągiem parametrów metody, nad którą pracujesz.

    [HttpGet]

    public async Task<IActionResult> ManageUserRoles(string userId)
    {

          ViewBag.UserId = userId;


        var user = await userManager.FindByIdAsync(userId);

        if (user == null)
        {
            ViewBag.ErrorMessage = $"User with Id = {userId} cannot be found";
            return View("NotFound");
        }

        var model = new List<UserRolesViewModel>();

        foreach (var role in roleManager.Roles)
        {
            var userRolesViewModel = new UserRolesViewModel
            {
                RoleId = role.Id,
                RoleName = role.Name
            };

            if (await userManager.IsInRoleAsync(user, role.Name))
            {
                userRolesViewModel.IsSelected = true;
            }
            else
            {
                userRolesViewModel.IsSelected = false;
            }

            model.Add(userRolesViewModel);
        }
        return View(model);
    }
sammy Akinsoju
źródło
-11

Jeśli chcesz to w kontrolerze ASP.NET MVC, użyj

using Microsoft.AspNet.Identity;

User.Identity.GetUserId();

Musisz dodać usingoświadczenie, ponieważ GetUserId()bez niego nie będzie.

Pravin Deshmukh
źródło
2
Tak, zawarłem w pytaniu, że mam „using Microsoft.AspNet.Identity”. Dowiedziałem się jednak, jak to rozwiązać, dzięki mojej odpowiedzi na poście
MRainzo,
1
FWIW to (teraz) User.GetUserId()a nieUser.Identity.GetUserId()
lc.
18
Pytanie brzmiało i jest abou asp.net CORE, który ma przestrzeń nazw Microsoft.AspNetCore.Identity; a NIE Microsoft.AspNet.Identity; Używając tej nowej przestrzeni nazw, NIE MA metody rozszerzenia GetUserId (). TA ODPOWIEDŹ JEST ZŁA!
Pascal
4
Łatwy na WSZYSTKICH KAPTURACH I dowiedz się, jak być miłym w SO. stackoverflow.blog/2018/04/26/…
smoore4