web-dev-qa-db-ja.com

asp.netコアで現在のユーザーを取得する方法

電子メールなどのユーザーの情報を取得するために現在のユーザーを取得したいです。しかし、私はasp.netコアでそれをすることはできません。私はとても混乱していますこれは私のコードです。

コントローラのコンストラクタではHttpContextがほとんどnullです。各アクションにユーザーを参加させるのは良くありません。一度ユーザの情報を取得して、それらをViewDataに設定します。

    public DashboardController()
    {
        var user = HttpContext.User.GetUserId();
   }
79
Mehran Hafizi
User.FindFirst(ClaimTypes.NameIdentifier).Value

コンストラクタの編集

以下のコードが機能します。

public Controller(IHttpContextAccessor httpContextAccessor)
{
    var userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value 
}

RTM用に編集

IHttpContextAccessorを登録する必要があります。

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    }
114
adem caglin

それがうまくいく簡単な方法と私はチェックしました。

private readonly UserManager<IdentityUser> _userManager;
public CompetitionsController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

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

そうすればuser.Emailのようにこの変数のすべてのプロパティを使えます。これが誰かに役立つことを願っています。

35
Ahmad

Asp.NET Coreで現在のユーザーを取得する別の方法があります - そして、私はそれをここのどこかで見たと思います、SO ^^

// Stores UserManager
private readonly UserManager<ApplicationUser> _manager; 

// Inject UserManager using dependency injection.
// Works only if you choose "Individual user accounts" during project creation.
public DemoController(UserManager<ApplicationUser> manager)  
{  
    _manager = manager;  
}

// You can also just take part after return and use it in async methods.
private async Task<ApplicationUser> GetCurrentUser()  
{  
    return await _manager.GetUserAsync(HttpContext.User);  
}  

// Generic demo method.
public async Task DemoMethod()  
{  
    var user = await GetCurrentUser(); 
    string userEmail = user.Email; // Here you gets user email 
    string userId = user.Id;
}  

そのコードはDemoControllerという名前のコントローラーに送られます。両方を待たずには動作しません(コンパイルしません);)

22
Hekkaryk

現時点(2017年4月)では、次のように動作しているようです。

public string LoggedInUser => User.Identity;

少なくともController内では

15
Grandizer

私はHttpContextがコンストラクタ内でnullであることに非常に驚いたと言わざるを得ない。私はそれがパフォーマンス上の理由からだと確信しています。下記のようにIPrincipalを使用すると、コンストラクタに挿入されることを確認しました。基本的には受け入れられている答えと同じですが、よりインターフェース的な方法で行われます。


一般的な「現在のユーザーを取得するにはどうすればいいですか?」に対する回答を探しているこの質問を見つける人は、Controller.Userから直接Userにアクセスするだけです。ただし、これはアクションメソッド内でしか実行できません(コントローラはHttpContextでのみ実行されないため、パフォーマンス上の理由から)。

しかし - もしあなたが(OPがそうであったように)あなたがそれをコンストラクタの中で必要とするなら、または現在のユーザを必要とする他の注入可能なオブジェクトを作成する必要があるなら、以下はより良いアプローチです:

IPrincipalを注入してユーザーを取得します

最初にIPrincipalIIdentityに会う

public interface IPrincipal
{
    IIdentity Identity { get; }
    bool IsInRole(string role);
}

public interface IIdentity
{
    string AuthenticationType { get; }
    bool IsAuthenticated { get; }
    string Name { get; }
}

IPrincipalIIdentityは、ユーザーとユーザー名を表します。 'Principal'が変に聞こえればWikipediaはあなたを慰めてくれます

IHttpContextAccessor.HttpContext.UserControllerBase.UserControllerBase.HttpContext.Userのいずれから取得した場合でも、ClaimsPrincipalを実装するIPrincipalオブジェクトであることが保証されているオブジェクトを取得することを理解することが重要です。

現時点でASP.NETがUserに使用している他の種類のユーザーはありません(ただし、他のものでIPrincipalを実装できないということではありません)。

したがって、注入したい「現在のユーザー名」の依存関係を持つものがある場合は、IPrincipalを注入する必要があります。IHttpContextAccessorは注入しないでください。

重要: IPrincipalを直接あなたのコントローラやアクションメソッドに注入するのに時間を浪費しないでください - Userはすでにそこにあるので、無意味です。

startup.cs内:

   // Inject IPrincipal
   services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);

ユーザーを必要とするDIオブジェクトでは、現在のユーザーを取得するためにIPrincipalを注入するだけです。

ここで最も重要なことは、HttpContextを送信する必要はなく、単なるIPrincipalこれも可能ClaimsPrincipalを送信する必要はないということです。

私が100%確信していないという1つの余分な重要なこと。 ClaimsPrincipalの実際の申し立てにアクセスする必要がある場合は、IPrincipalClaimsPrincipalにキャストする必要があります。実行時にそれがその型であることを100%知っているのでこれは問題ありません(それがHttpContext.Userの意味です)。 IPrincipalClaimsPrincipalになることはすでにわかっているので、実際にはコンストラクタでこれを実行するだけです。

あなたがモックをしているのであれば、 直接ClaimsPrincipalを作成してください _とそれをIPrincipalを必要とするものすべてに渡してください。

IClaimsPrincipal用のインターフェースがないのは正確な理由はわかりません。私は、MSがClaimsPrincipalは単にインターフェースを保証するものではない特殊な「コレクション」であると判断したと思います。

5
Simon_Weaver

私の問題は、cshtmlファイル内のオブジェクトとしてログインユーザーにアクセスすることでした。 ViewDataにユーザーが欲しいと考えると、このアプローチは役に立ちます。

Cshtmlファイル内

@using Microsoft.AspNetCore.Identity
@inject UserManager<ApplicationUser> UserManager

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>
    @UserManager.FindByNameAsync(UserManager.GetUserName(User)).Result.Email
    </title>
  </head>
  <body>

  </body>
</html>
3
MikeMajara

既存の回答に加えて、UserIDなどのユーザー関連データを保持するクラスインスタンスをアプリ全体で利用できるようにすることもできます。

リファクタリングたとえば、すべてのコントローラアクションでUserIDを取得し、関連するすべてのメソッドで追加のUserIDパラメータを宣言したくない場合など)に役立ちます。サービス層へ。

私は研究をしました、そしてここに 私の投稿 があります。

DbContextプロパティを追加することでUserIdから派生するクラスを拡張するだけです(またはこのプロパティを持つカスタムのSessionクラスを実装します)。

フィルタレベルでは、クラスインスタンスを取得してUserIdの値を設定することができます。

その後、インスタンスを注入した場所には、必要なデータがあります(有効期間は要求ごとにする必要があるため、AddScopedメソッドを使用して登録します)。

作業例:

public class AppInitializationFilter : IAsyncActionFilter
{
    private DBContextWithUserAuditing _dbContext;

    public AppInitializationFilter(
        DBContextWithUserAuditing dbContext
        )
    {
        _dbContext = dbContext;
    }

    public async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next
        )
    {
        string userId = null;
        int? tenantId = null;

        var claimsIdentity = (ClaimsIdentity)context.HttpContext.User.Identity;

        var userIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
        if (userIdClaim != null)
        {
            userId = userIdClaim.Value;
        }

        var tenantIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == CustomClaims.TenantId);
        if (tenantIdClaim != null)
        {
            tenantId = !string.IsNullOrEmpty(tenantIdClaim.Value) ? int.Parse(tenantIdClaim.Value) : (int?)null;
        }

        _dbContext.UserId = userId;
        _dbContext.TenantId = tenantId;

        var resultContext = await next();
    }
}

詳しくは 私の答え をご覧ください。

1
Alex Herman

ScafoldedIdentityを使用し、Asp.net Core 2.2+を使用している場合、次のようなビューから現在のユーザーにアクセスできます。

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

 @if (SignInManager.IsSignedIn(User))
    {
        <p>Hello @User.Identity.Name!</p>
    }
    else
    {
        <p>You're not signed in!</p>
    }

https://docs.Microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.2&tabs=visual-studio

0
Andrew

IdentityUserを取ることでもうまくいくでしょう。これは現在のユーザーオブジェクトであり、userのすべての値を取得できます。

private readonly UserManager<IdentityUser> _userManager;
public yourController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

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

これは古い質問ですが、私のケースは、ここで議論されていないことを示しています。

Simon_Weaverの答えが一番気に入っています( https://stackoverflow.com/a/54411397/290389 )。彼は、IPrincipalとIIdentityを使用してユーザー名を取得する方法を詳細に説明します。この答えは絶対に正しいので、このアプローチを使用することをお勧めします。ただし、デバッグ中にASP.NETがサービスプリンシパルを適切に設定できない場合に問題が発生しました。 (つまり、IPrincipal.Identity.Nameはnullです)

ユーザー名を取得するには、MVCフレームワークがどこかから取得する必要があることは明らかです。 .NETの世界では、ASP.NETまたはASP.NET CoreはOpen ID Connectミドルウェアを使用しています。単純なシナリオでは、WebアプリはWebブラウザーでユーザーを認証します。このシナリオでは、WebアプリケーションはユーザーのブラウザーにAzure ADにサインインするよう指示します。 Azure ADは、ユーザーのブラウザーを介してサインイン応答を返します。ブラウザーには、セキュリティトークンにユーザーに関するクレームが含まれています。アプリケーションのコードで機能させるには、Webアプリがサインインを委任する権限を提供する必要があります。 WebアプリをAzureサービスにデプロイする場合、この要件を満たす一般的なシナリオは、Webアプリを構成することです:「App Services」-> YourApp->「Authentication/Authorization」ブレード->「App Service Authenticatio」=「On」などon( https://github.com/Huachao/Azure-content/blob/master/articles/app-service-api/app-service-api-authentication.md ))私は、このプロセスの裏側で、​​ウィザードが以下の段落で示すのと同じ設定を追加することにより、このWebアプリの「親」Web構成を調整すると信じています(これは私の経験に基づく推測です)。基本的に、このアプローチがASP.NET Coreで機能しない理由は、「親」マシン構成がwebconfigによって無視されるためです。 (これは100%確実ではありません。私が持っている最高の説明をするだけです)。そのため、動作させるには、アプリで手動でセットアップする必要があります。

ここに、Azure ADを使用するようにアプリを多数セットアップする方法を説明する記事があります。 https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/aspnetcore2-2

ステップ1:サンプルをAzure ADテナントに登録します。 (明らかに、私の説明の時間を費やしたくない)。

手順2:appsettings.jsonファイルで、ClientID値を手順1でアプリケーション登録ポータルに登録したアプリケーションのアプリケーションIDに置き換えます。TenantId値をcommonに置き換えます

ステップ3:Startup.csファイルを開き、ConfigureServicesメソッドで、.AddAzureADを含む行に次のコードを挿入した後、アプリケーションがAzure AD v2.0エンドポイント、つまりWorkとSchoolの両方でユーザーをサインインできるようにします。 Microsoft Personalアカウント。

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.Authority = options.Authority + "/v2.0/";
    options.TokenValidationParameters.ValidateIssuer = false;
});

概要:トピックスターターが説明されているエラーにつながる可能性のあるもう1つの可能性のある問題を示しました。この問題の理由は、Azure AD(Open IDミドルウェア)の構成がないことです。この問題を解決するために、「Authentication/Authorization」を手動でセットアップすることを提案します。これをセットアップする方法の簡単な概要が追加されます。

0
Roman Oira-Oira

おそらく私は答えを見ませんでしたが、これは私がそれをする方法です。

  1. 。Net Core->プロパティ-> launchSettings.json

これらの値を変更する必要があります

"windowsAuthentication": true, // needs to be true
"anonymousAuthentication": false,  // needs to be false 

Startup.cs-> ConfigureServices(...)

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

MVCまたはWeb Apiコントローラー

private readonly IHttpContextAccessor _httpContextAccessor;
//constructor then
_httpContextAccessor = httpContextAccessor;

コントローラー方式:

string userName = _httpContextAccessor.HttpContext.User.Identity.Name;

結果はuserNameです。 =ドメイン\ユーザー名

0
Tom Stickel