web-dev-qa-db-ja.com

User.Identityの利用可能なプロパティを拡張する方法

認証の詳細がSQLデータベースに保存されている自分のWebサイトにユーザーがログインするためにMVC5 Identity 2.0を使用しています。 Asp.netのIDは、多くのオンラインチュートリアルで見られるように標準的な方法で実装されています。

IdentityModelsのApplicationUserクラスは、整数のOrganizationIdなどのカスタムプロパティを含むように拡張されました。データベースの関係を目的として、多くのユーザーを作成して共通の組織に割り当てることができます。

public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }

        //Extended Properties
        public DateTime? BirthDate { get; set; }
        public long? OrganizationId { get; set; }

        //Key Mappings
        [ForeignKey("OrganizationId")]
        public virtual Organization Organization { get; set; }
    }

コントローラ内から現在ログインしているユーザのOrganizationIdプロパティを取得する方法を教えてください。これは、ユーザがログインした後でメソッドを介して利用できるか、またはコントローラメソッドが実行されるたびに、常にUserIdに基づいてデータベースからOrganizationIdを取得する必要がありますか?

私は見たことがあるウェブ上で読み回って、私はログインしたUserIdなどを得るために以下を使う必要があります。

using Microsoft.AspNet.Identity;
...
User.Identity.GetUserId();

ただし、OrganizationIdはUser.Identityで使用できるプロパティではありません。 OrganizationIdプロパティを含めるためにUser.Identityを拡張する必要がありますか?もしそうなら、どうやってこれをやりますか。

私が頻繁にOrganizationIdを必要とするのは、ログインしたユーザーに関連付けられている組織に関連するデータを取得するために、多くのテーブルクエリがOrganizationIdに依存しているためです。

117
RobHurd

上記の質問のようにUser.Identityのプロパティを追加のプロパティで拡張したい場合は、まず次のようにApplicationUserクラスにこれらのプロパティを追加します。

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }

    // Your Extended Properties
    public long? OrganizationId { get; set; }
}

それならあなたが必要とするのはそのような拡張メソッドを作成することです(私は新しいExtensionsフォルダに私のものを作成します):

namespace App.Extensions
{
    public static class IdentityExtensions
    {
        public static string GetOrganizationId(this IIdentity identity)
        {
            var claim = ((ClaimsIdentity)identity).FindFirst("OrganizationId");
            // Test for null to avoid issues during local testing
            return (claim != null) ? claim.Value : string.Empty;
        }
    }
}

ApplicationUserクラスにIdentityを作成したら、Claim - > OrganizationIdを追加します。

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here => this.OrganizationId is a value stored in database against the user
        userIdentity.AddClaim(new Claim("OrganizationId", this.OrganizationId.ToString()));

        return userIdentity;
    }

あなたがUser.Identityのプロパティとしてそれを利用できるようにするために、クレームを追加して、あなたの拡張メソッドをきちんと整えさせたら、あなたがそれにアクセスしたいページ/ファイルにusingステートメントを追加する

私の場合は、Controller内のusing App.Extensions;と.cshtml Viewファイルを含む@using. App.Extensionsです。

編集:

また、すべてのビューにusingステートメントを追加しないようにするには、Viewsフォルダーに移動してその中のWeb.configファイルを見つけます。今度は<namespaces>タグを探して、そのようにあなたの拡張名前空間をそこに追加してください:

<add namespace="App.Extensions" />

ファイルを保存すれば完了です。今すぐすべてのビューがあなたの拡張機能を知っているでしょう。

拡張メソッドにアクセスすることができます。

var orgId = User.Identity.GetOrganizationId();

誰にでも役立つことを願っています:)

203
Pawel

私は同じ解決策を探していました、そしてPawelは私に答えの99%を与えました。拡張機能を表示するために必要なことが欠けていた唯一のことは、cshtml(view)ページに次のかみそりコードを追加することでした。

@using programname.Models.Extensions

ユーザーがログインした後、私のNavBarの右上に表示するFirstNameを探していました。

私はこの記事を投稿することを考えています。

Extensionsという新しいフォルダを(私のModelsフォルダの下に)作成し、Pawelが上記で指定したとおりに新しいクラスを作成しました。IdentityExtensions.cs

using System.Security.Claims;
using System.Security.Principal;

namespace ProgramName.Models.Extensions
{
    public static class IdentityExtensions
    {
        public static string GetUserFirstname(this IIdentity identity)
        {
            var claim = ((ClaimsIdentity)identity).FindFirst("FirstName");
            // Test for null to avoid issues during local testing
            return (claim != null) ? claim.Value : string.Empty;
        }
    }
}

IdentityModels.cs

public class ApplicationUser : IdentityUser
{

    //Extended Properties
    public string FirstName { get; internal set; }
    public string Surname { get; internal set; }
    public bool isAuthorized { get; set; }
    public bool isActive { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        userIdentity.AddClaim(new Claim("FirstName", this.FirstName));

        return userIdentity;
    }
}

それから私の_LoginPartial.cshtmlViews/Sharedフォルダの下)に@using.ProgramName.Models.Extensionsを追加しました

次に、ログイン後にユーザーのファーストネームを使用することになる、次のコード行に変更を加えました。

@Html.ActionLink("Hello " + User.Identity.GetUserFirstname() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })

おそらくこれは他の誰かを助けます。

15
AxleWack

John Attenによるこの素晴らしいブログ投稿をチェックしてください。 ASP.NET Identity 2.0:ユーザーとロールのカスタマイズ

それはプロセス全体に関する素晴らしいステップバイステップの情報を持っています。それを読みに行く:)

ここにいくつかの基本があります。

新しいプロパティ(Address、City、Stateなど)を追加して、デフォルトのApplicationUserクラスを拡張します。

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> 
    GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this,  DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }

    // Use a sensible display name for views:
    [Display(Name = "Postal Code")]
    public string PostalCode { get; set; }

    // Concatenate the address info for display in tables and such:
    public string DisplayAddress
    {
        get
        {
            string dspAddress = string.IsNullOrWhiteSpace(this.Address) ? "" : this.Address;
            string dspCity = string.IsNullOrWhiteSpace(this.City) ? "" : this.City;
            string dspState = string.IsNullOrWhiteSpace(this.State) ? "" : this.State;
            string dspPostalCode = string.IsNullOrWhiteSpace(this.PostalCode) ? "" : this.PostalCode;

            return string.Format("{0} {1} {2} {3}", dspAddress, dspCity, dspState, dspPostalCode);
        }
    }

それから、あなたのRegisterViewModelにあなたの新しいプロパティを追加します。

    // Add the new address properties:
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }

それから、Register Viewを更新して新しいプロパティを含めます。

    <div class="form-group">
        @Html.LabelFor(m => m.Address, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Address, new { @class = "form-control" })
        </div>
    </div>

次に、新しいプロパティでAccountControllerのRegister()メソッドを更新します。

    // Add the Address properties:
    user.Address = model.Address;
    user.City = model.City;
    user.State = model.State;
    user.PostalCode = model.PostalCode;
10
Dhaust

ASP.NET Core 2.1でカスタムプロパティにアクセスする方法を探しているこの質問を見つけた人のために - それははるかに簡単です:あなたはUserManagerを持っているでしょう。 _LoginPartial.cshtmlに追加して、簡単に実行できます( "ScreenName"は、IdentityUserから継承した独自のAppUserに追加したプロパティです)。

@using Microsoft.AspNetCore.Identity

@using <namespaceWhereYouHaveYourAppUser>

@inject SignInManager<AppUser> SignInManager
@inject UserManager<AppUser> UserManager

@if (SignInManager.IsSignedIn(User)) {
    <form asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new { area = "" })" 
          method="post" id="logoutForm" 
          class="form-inline my-2 my-lg-0">

        <ul class="nav navbar-nav ml-auto">
            <li class="nav-item">
                <a class="nav-link" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">
                    Hello @((await UserManager.GetUserAsync(User)).ScreenName)!
                    <!-- Original code, shows Email-Address: @UserManager.GetUserName(User)! -->
                </a>
            </li>
            <li class="nav-item">
                <button type="submit" class="btn btn-link nav-item navbar-link nav-link">Logout</button>
            </li>
        </ul>

    </form>
} else {
    <ul class="navbar-nav ml-auto">
        <li class="nav-item"><a class="nav-link" asp-area="Identity" asp-page="/Account/Register">Register</a></li>
        <li class="nav-item"><a class="nav-link" asp-area="Identity" asp-page="/Account/Login">Login</a></li>
    </ul>
}
2
Jashan

Dhaustは、ApplicationUserクラスにプロパティを追加するための優れた方法を提供します。 OPコードを見ると、彼らはこれを行ったか、またはそれを順調に進んでいたようです。質問は尋ねます

コントローラ内から現在ログインしているユーザのOrganizationIdプロパティを取得する方法を教えてください。ただし、OrganizationIdはUser.Identityで使用できるプロパティではありません。 OrganizationIdプロパティを含めるためにUser.Identityを拡張する必要がありますか?

Pawelは、ステートメントの使用やweb.configファイルへの名前空間の追加を必要とする拡張メソッドを追加する方法を提供します。

ただし、質問では、新しいプロパティを含めるためにUser.Identityを "拡張"する必要があるかどうかを尋ねられます。 User.Identityを拡張せずにプロパティにアクセスする別の方法があります。 Dhaustメソッドに従った場合は、コントローラで次のコードを使用して新しいプロパティにアクセスできます。

ApplicationDbContext db = new ApplicationDbContext();
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
var currentUser = manager.FindById(User.Identity.GetUserId());
var myNewProperty = currentUser.OrganizationId;
1
codeMethod

また、AspNetUsersテーブルに追加の列を追加または拡張しました。このデータを単純に見たかったときに、 "Extensions"などを使って上記のコードのような多くの例を見つけました。

AspNetUsersテーブルを他のテーブルと同じようにクエリできることがわかりました。

 ApplicationDbContext db = new ApplicationDbContext();
 var user = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault();
0
Anthony Griggs