電子メールなどのユーザーの情報を取得するために現在のユーザーを取得したいです。しかし、私はasp.netコアでそれをすることはできません。私はとても混乱していますこれは私のコードです。
コントローラのコンストラクタではHttpContext
がほとんどnullです。各アクションにユーザーを参加させるのは良くありません。一度ユーザの情報を取得して、それらをViewData
に設定します。
public DashboardController()
{
var user = HttpContext.User.GetUserId();
}
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>();
}
それがうまくいく簡単な方法と私はチェックしました。
private readonly UserManager<IdentityUser> _userManager;
public CompetitionsController(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
var user = await _userManager.GetUserAsync(HttpContext.User);
そうすればuser.Email
のようにこの変数のすべてのプロパティを使えます。これが誰かに役立つことを願っています。
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という名前のコントローラーに送られます。両方を待たずには動作しません(コンパイルしません);)
現時点(2017年4月)では、次のように動作しているようです。
public string LoggedInUser => User.Identity;
少なくともController
内では
私はHttpContextがコンストラクタ内でnullであることに非常に驚いたと言わざるを得ない。私はそれがパフォーマンス上の理由からだと確信しています。下記のようにIPrincipal
を使用すると、コンストラクタに挿入されることを確認しました。基本的には受け入れられている答えと同じですが、よりインターフェース的な方法で行われます。
一般的な「現在のユーザーを取得するにはどうすればいいですか?」に対する回答を探しているこの質問を見つける人は、Controller.User
から直接User
にアクセスするだけです。ただし、これはアクションメソッド内でしか実行できません(コントローラはHttpContextでのみ実行されないため、パフォーマンス上の理由から)。
しかし - もしあなたが(OPがそうであったように)あなたがそれをコンストラクタの中で必要とするなら、または現在のユーザを必要とする他の注入可能なオブジェクトを作成する必要があるなら、以下はより良いアプローチです:
最初にIPrincipal
とIIdentity
に会う
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipal
とIIdentity
は、ユーザーとユーザー名を表します。 'Principal'が変に聞こえればWikipediaはあなたを慰めてくれます 。
IHttpContextAccessor.HttpContext.User
、ControllerBase.User
、ControllerBase.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
の実際の申し立てにアクセスする必要がある場合は、IPrincipal
をClaimsPrincipal
にキャストする必要があります。実行時にそれがその型であることを100%知っているのでこれは問題ありません(それがHttpContext.User
の意味です)。 IPrincipal
がClaimsPrincipal
になることはすでにわかっているので、実際にはコンストラクタでこれを実行するだけです。
あなたがモックをしているのであれば、 直接ClaimsPrincipal
を作成してください _とそれをIPrincipal
を必要とするものすべてに渡してください。
IClaimsPrincipal
用のインターフェースがないのは正確な理由はわかりません。私は、MSがClaimsPrincipal
は単にインターフェースを保証するものではない特殊な「コレクション」であると判断したと思います。
私の問題は、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>
既存の回答に加えて、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();
}
}
詳しくは 私の答え をご覧ください。
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>
}
IdentityUser
を取ることでもうまくいくでしょう。これは現在のユーザーオブジェクトであり、userのすべての値を取得できます。
private readonly UserManager<IdentityUser> _userManager;
public yourController(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
var user = await _userManager.GetUserAsync(HttpContext.User);
これは古い質問ですが、私のケースは、ここで議論されていないことを示しています。
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」を手動でセットアップすることを提案します。これをセットアップする方法の簡単な概要が追加されます。
おそらく私は答えを見ませんでしたが、これは私がそれをする方法です。
これらの値を変更する必要があります
"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です。 =ドメイン\ユーザー名