ASP.NET Core ID-현재 사용자 가져 오기


83

MVC5에서 현재 로그인 한 사용자를 얻으려면 다음과 같이해야합니다.

using Microsoft.AspNet.Identity;
[Authorize]
public IHttpActionResult DoSomething() {
    string currentUserId = User.Identity.GetUserId();
}

이제 ASP.NET Core를 사용하면 이것이 작동한다고 생각했지만 오류가 발생합니다.

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Http;

private readonly UserManager<ApplicationUser> _userManager;
[HttpPost]
[Authorize]
public async Task<IActionResult> StartSession() {
    var curUser = await _userManager.GetUserAsync(HttpContext.User);
}

어떤 아이디어?

편집 : Gerardo의 응답은 궤도에 있지만 사용자의 실제 "ID"를 얻으려면 작동하는 것 같습니다.

ClaimsPrincipal currentUser = this.User;
var currentUserID = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;

당신의 질문은 정확히 무엇입니까?
Gerardo Grignoli

이드 만 있으면 돼? 내가 어떻게 더 멋진 _userManager.GetUserId (사용자)를 사용하여 얻을 추가 내 대답을 편집
제라르 Grignoli

예, 주로 AspNetUsers 테이블 또는 세션의 Id가 필요합니다. currentUser.FindFirst (ClaimTypes.NameIdentifier) ​​.Value는 클레임을 사용하여 Id를 제공합니다. UserManager에서도 작동합니다! Gerardo 감사합니다! 한 가지 방법이 다른 것보다 효율적입니까?
jbraun 2016-08-04

UserManager는 내부적으로 .FindFirst (ClaimTypes.NameIdentifier)를 수행합니다. 따라서 성능면에서 동일합니다. 읽기 쉽도록 usermanager 캡슐화를 선호합니다. 반면에 .GetUserAsync()DB로 이동하기 때문에 느립니다.
Gerardo

나는 Gerardo에 완전히 동의합니다. 감사합니다 !
jbraun

답변:


144

코드가 MVC 컨트롤러 내부에 있다고 가정합니다.

public class MyController : Microsoft.AspNetCore.Mvc.Controller

로부터 Controller기본 클래스, 당신은 얻을 수 있습니다 IClaimsPrincipal으로부터 User재산

System.Security.Claims.ClaimsPrincipal currentUser = this.User;

청구를 직접 확인할 수 있습니다 (데이터베이스로의 왕복없이).

bool IsAdmin = currentUser.IsInRole("Admin");
var id = _userManager.GetUserId(User); // Get user id:

데이터베이스의 User 엔티티에서 다른 필드를 가져올 수 있습니다.

  1. 종속성 주입을 사용하여 사용자 관리자 가져 오기

    private UserManager<ApplicationUser> _userManager;
    
    //class constructor
    public MyController(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }
    
  2. 그리고 그것을 사용하십시오 :

    var user = await _userManager.GetUserAsync(User);
    var email = user.Email;
    

6
컨트롤러가 아닌 서비스 클래스에있는 경우 사용자 속성이 없습니까? 인증 된 사용자의 AppUser-Object를 얻는 방법은 무엇입니까?
Kirsten

13
@Kirsten IHttpContextAccessorwith Dependency Injection을 수신 한 다음 Userhttp 컨텍스트에서 가져올 수 있습니다 . 이 매개 변수를 서비스 클래스 생성자에 추가하기 만하면 IHttpContextAccessor contextAccessor됩니다.. 접근자를 필드에 유지 한 _contextAccessor다음 서비스 메서드에서 _contextAccessor.HttpContext.User.
Gerardo Grignoli

5
@Kirsten하지만 이렇게하면 서비스가 ASP.NET Core와 결합되어 다른 종류의 시나리오에서는 사용할 수 없게됩니다. 이것은 귀하에게 허용 될 수도 있고 아닐 수도 있습니다. 메서드 호출에서 서비스에 원하는 것을 정확히 전달하는 것도 고려할 것입니다.
Gerardo Grignoli

2
당신은 저를 올바른 방법으로 밀었습니다. 저는 GetUser와 IsAuthenticated로 IUserService를 만들었습니다. 내 ASP.NET Core 앱에는 IHttpContextAccessor와 UserManager <ApplicationUser>를 사용하는 userService 구현이 있습니다. 따라서 내 userService는 ASP.NET Core에 연결되지만 다른 서비스는 그렇지 않습니다.
Kirsten

2
아니요, 그들은 데이터베이스에 가지 않습니다. 소스를 확인하면 UserStore를 사용하지 않습니다. github.com/dotnet/corefx/blob/master/src/System.Security.Claims/... github.com/aspnet/Identity/blob/...
제라르 Grignoli

34

베어링 토큰 인증을 사용하는 경우 위 샘플은 애플리케이션 사용자를 반환하지 않습니다.

대신 다음을 사용하십시오.

ClaimsPrincipal currentUser = this.User;
var currentUserName = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;
ApplicationUser user = await _userManager.FindByNameAsync(currentUserName);

이것은 apsnetcore 2.0에서 작동합니다. 이전 버전에서 시도하지 않았습니다.


내 토큰의 유효성을 검사하고 있지만 주체와 클레임이 설정되지 않았습니다.
dotnet

@ ps2goat,이 문제를 해결하기 위해 새 질문을 만들고 토큰을 만드는 코드를 포함합니다.
Greg Gum

1
나는 그것을 알아. 5 개의 다른 체계가 있기 때문에 기본 체계가 없습니다. 토큰을 디코딩하고 현재 사용자에게 클레임을 할당하기 위해 미들웨어를 추가해야했습니다. 내 상황에 대한 내용이 거의 없기 때문에 질문을 작성하고 다른 사람들을 위해 대답해야합니다.
ps2goat

1
ClaimTypes.Name은 Id 대신 내가 찾고 있던 사용자 이름을 가져옵니다. ClaimTypes.NameIdentifier는 사용자의 ID를 가져옵니다. 누군가 이것을보고 사용자 이름을 얻는 방법을 궁금해하는 경우를 대비하여. 귀하의 답변 Greg에 감사드립니다!
Matthew Zourelias

7

컨텍스트를 위해 ASP.NET Core 2 웹 애플리케이션 템플릿을 사용하여 프로젝트를 만들었습니다. 그런 다음 웹 애플리케이션 (MVC)을 선택한 다음 인증 변경 버튼을 누르고 개별 사용자 계정을 선택합니다.

이 템플릿을 통해 구축 된 많은 인프라가 있습니다. ManageControllerControllers 폴더에서 찾습니다 .

ManageController클래스 생성자는 다음 UserManager 변수를 채워야합니다.

private readonly UserManager<ApplicationUser> _userManager;

그런 다음이 클래스의 [HttpPost] Index 메서드를 살펴보십시오. 그들은 다음과 같은 방식으로 현재 사용자를 얻습니다.

var user = await _userManager.GetUserAsync(User);

참고로 여기에서 AspNetUsers 테이블에 추가 한 사용자 프로필에 대한 사용자 지정 필드를 업데이트 할 수 있습니다. 뷰에 필드를 추가 한 다음 해당 값을 IndexViewModel에 제출 한 다음이 Post 메서드에 제출합니다. 이메일 주소와 전화 번호를 설정하는 기본 로직 뒤에이 코드를 추가했습니다.

user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.Address1 = model.Address1;
user.Address2 = model.Address2;
user.City = model.City;
user.State = model.State;
user.Zip = model.Zip;
user.Company = model.Company;
user.Country = model.Country;
user.SetDisplayName();
user.SetProfileID();

_dbContext.Attach(user).State = EntityState.Modified;
_dbContext.SaveChanges();

5

.NET Core 2.0에서 사용자는 이미 상속 된 기본 컨트롤러의 일부로 존재합니다. 평상시처럼 사용자를 사용하거나 저장소 코드로 전달하십시오.

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Policy = "TENANT")]
[HttpGet("issue-type-selection"), Produces("application/json")]
public async Task<IActionResult> IssueTypeSelection()
{
    try
    {
        return new ObjectResult(await _item.IssueTypeSelection(User));
    }
    catch (ExceptionNotFound)
    {
        Response.StatusCode = (int)HttpStatusCode.BadRequest;
        return Json(new
        {
            error = "invalid_grant",
            error_description = "Item Not Found"
        });
    }
}

이것은 그것을 상속받는 곳입니다.

#region Assembly Microsoft.AspNetCore.Mvc.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// C:\Users\BhailDa\.nuget\packages\microsoft.aspnetcore.mvc.core\2.0.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Core.dll
#endregion

using System;
using System.IO;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Routing;
using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.Mvc
{
    //
    // Summary:
    //     A base class for an MVC controller without view support.
    [Controller]
    public abstract class ControllerBase
    {
        protected ControllerBase();

        //
        // Summary:
        //     Gets the System.Security.Claims.ClaimsPrincipal for user associated with the
        //     executing action.
        public ClaimsPrincipal User { get; }

2

누군가 관심이 있다면 이것이 나를 위해 일했습니다. 기본 키에 int를 사용하는 사용자 지정 ID가 있으므로 GetUserAsync 메서드를 재정의했습니다.

GetUserAsync 재정의

public override Task<User> GetUserAsync(ClaimsPrincipal principal)
{
    var userId = GetUserId(principal);
    return FindByNameAsync(userId);
}

ID 사용자 얻기

var user = await _userManager.GetUserAsync(User);

일반 Guid 기본 키를 사용하는 경우 GetUserAsync를 재정의 할 필요가 없습니다. 이것은 모두 토큰이 올바르게 구성되었다고 가정합니다.

public async Task<string> GenerateTokenAsync(string email)
{
    var user = await _userManager.FindByEmailAsync(email);
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(_tokenProviderOptions.SecretKey);

    var userRoles = await _userManager.GetRolesAsync(user);
    var roles = userRoles.Select(o => new Claim(ClaimTypes.Role, o));

    var claims = new[]
    {
        new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
        new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString(CultureInfo.CurrentCulture)),
        new Claim(JwtRegisteredClaimNames.GivenName, user.FirstName),
        new Claim(JwtRegisteredClaimNames.FamilyName, user.LastName),
        new Claim(JwtRegisteredClaimNames.Email, user.Email),
    }
    .Union(roles);

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(claims),
        Expires = DateTime.UtcNow.AddHours(_tokenProviderOptions.Expires),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);

    return Task.FromResult(new JwtSecurityTokenHandler().WriteToken(token)).Result;
}

1
private readonly UserManager<AppUser> _userManager;

 public AccountsController(UserManager<AppUser> userManager)
 {
            _userManager = userManager;
 }

[Authorize(Policy = "ApiUser")]
[HttpGet("api/accounts/GetProfile", Name = "GetProfile")]
public async Task<IActionResult> GetProfile()
{
   var userId = ((ClaimsIdentity)User.Identity).FindFirst("Id").Value;
   var user = await _userManager.FindByIdAsync(userId);

   ProfileUpdateModel model = new ProfileUpdateModel();
   model.Email = user.Email;
   model.FirstName = user.FirstName;
   model.LastName = user.LastName;
   model.PhoneNumber = user.PhoneNumber;

   return new OkObjectResult(model);
}

0

내 Controller 클래스에 다음과 같은 것을 넣었고 작동했습니다.

IdentityUser user = await userManager.FindByNameAsync(HttpContext.User.Identity.Name);

여기서 userManager는 Microsoft.AspNetCore.Identity.UserManager 클래스의 인스턴스입니다 (모든 이상한 설정 포함).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.