ASP.NET CoreIdentity-現在のユーザーを取得する


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

IDだけが必要ですか?より派手な_userManager.GetUserId(User)を使用して取得する方法を追加するために回答を編集しました
Gerardo Grignoli

はい、主にAspNetUsersテーブルまたはセッションからのIDが必要です。currentUser.FindFirst(ClaimTypes.NameIdentifier).Valueは、クレームを使用してIDを提供します。UserManagerでも動作します!ジェラルドありがとう!一方の方法はもう一方の方法よりも効率的ですか?
jbraun 2016

UserManagerは内部的に.FindFirst(ClaimTypes.NameIdentifier)を実行します。したがって、パフォーマンスに関しても同じです。読みやすくするために、usermanagerのカプセル化を好みます。一方.GetUserAsync()、DBに送られるため、速度は遅くなります。
Gerardo Grignoli 2016

ジェラルドに完全に同意します。ありがとうございました !
jbraun 2016

回答:


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:

その他のフィールドは、データベースのユーザーエンティティから取得できます。

  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を取得するにはどうすればよいですか?
キルステン2016

13
@KirstenIHttpContextAccessor依存性注入を使用して受信Userし、httpコンテキストから取得できます。このパラメーターをサービスクラスコンストラクターに追加するだけです IHttpContextAccessor contextAccessor。アクセサをフィールドに保持し_contextAccessorてから、サービスメソッドでから取得し_contextAccessor.HttpContext.Userます。
Gerardo Grignoli 2016

5
@Kirstenただし、これを行うと、サービスがASP.NET Coreと結合され、他の種類のシナリオでは使用できなくなります。これはあなたにとって受け入れられるかもしれないし、受け入れられないかもしれません。また、メソッド呼び出しで必要なものをサービスに正確に渡すことも検討します。
Gerardo Grignoli 2016

2
あなたは私を正しい方法でプッシュしました:私はGetUserとIsAuthenticatedでIUserServiceを構築しました。ASP.NET Core Appには、IHttpContextAccessorとUserManager <ApplicationUser>を使用する実装userServiceがあります。したがって、私のuserServiceはASP.NET Coreに結合されていますが、他のサービスは結合されていません。
キルステン

2
いいえ、データベースにはアクセスしません。ソースを確認すると、UserStoreを使用していません。github.com/dotnet/corefx/blob/master/src/System.Security.Claims/…github.com/aspnet/Identity/blob/…–
Gerardo Grignoli

34

Bearing Token Authを使用している場合、上記のサンプルはアプリケーションユーザーを返しません。

代わりに、これを使用してください:

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

これはapsnetcore2.0で機能します。以前のバージョンでは試していません。


トークンは検証されていますが、プリンシパルとクレームが設定されていません。これはDOTNETコア2.1と2.2で何が起こっている
ps2goat

@ ps2goat、これに対処するための新しい質問を作成し、トークンを作成しているコードを含めます。
グレッグガム

1
私はそれを考え出した。5つの異なるスキームがあるため、デフォルトのスキームはありません。トークンをデコードし、現在のユーザーにクレームを割り当てるためにミドルウェアを追加する必要がありました。私の状況に関する内容はほとんどないので、おそらく質問を書いて他の人のために答えるべきです。
ps2goat

1
ClaimTypes.Nameは、IDの代わりに探していたユーザー名を取得します。ClaimTypes.NameIdentifierは、ユーザーのIDを取得します。誰かがこれを見て、ユーザー名を取得する方法を疑問に思っている場合に備えて。あなたの答えをありがとうグレッグ!
MatthewZourelias19年

7

コンテキストとして、ASP.NET Core 2Webアプリケーションテンプレートを使用してプロジェクトを作成しました。次に、Webアプリケーション(MVC)を選択し、[認証の変更]ボタンを押して、[個々のユーザーアカウント]を選択します。

このテンプレートから構築された多くのインフラストラクチャがあります。ManageControllerControllersフォルダーでを見つけます。

このManageControllerクラスコンストラクターでは、次のUserManager変数を設定する必要があります。

private readonly UserManager<ApplicationUser> _userManager;

次に、このクラスの[HttpPost] Indexメソッドを見てください。彼らはこの方法で現在のユーザーを取得します:

var user = await _userManager.GetUserAsync(User);

ボーナスノートとして、これは、AspNetUsersテーブルに追加したユーザープロファイルのカスタムフィールドを更新する場所です。フィールドをビューに追加してから、それらの値をIndexViewModelに送信し、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.