User.Identity의 사용 가능한 속성을 확장하는 방법


130

인증 세부 정보가 SQL 데이터베이스에 저장되는 사용자가 내 웹 사이트에 로그인 할 수 있도록 MVC5 Identity 2.0을 사용하고 있습니다. Asp.net Identity는 많은 온라인 자습서에서 볼 수있는 것처럼 표준 방식으로 구현되었습니다.

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에 의존하여 로그인 한 사용자와 연관된 조직과 관련된 데이터를 검색하기 때문입니다.


3
여기에 내 대답이 전혀 도움이 되나요?
구두

1
여기에서 나와 거의 같은 대답이 있습니다 : stackoverflow.com/a/28138594/809357- 요청 기간 동안이 정보가 정기적으로 필요한 경우 쿠키로 청구 할 수 있습니다.
trailmax

1
감사합니다 @ 신발 모두 답이 작동했습니다. 귀하의 답변 외에도 쿠키에 저장 될 클레임을 추가해야했습니다. IdentityModels 클래스에서 userIdentity.AddClaim (new Claim ( "MyApp : OrganizationId", OrganizationId.ToString ())); 을 추가해야했습니다 . 받는 공용 작업 <ClaimsIdentity> GenerateUserIdentityAsync (UserManager <ApplicationUser> 관리자) 비동기 방법.
RobHurd

답변:


219

위의 질문과 같은 추가 속성을 사용하여 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; }
}

그런 다음 필요한 확장 방법을 만드는 것입니다 (새 확장 폴더에 광산을 만듭니다).

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 클래스에서 아이디를 만들 때 다음과 같이 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 문을 추가하십시오 .

내 경우에는 : using App.Extensions;Controller 내 @using. App.Extensions에서 .cshtml View 파일 사용.

편집하다:

모든 View에 using 문을 추가하지 않도록 할 수있는 작업은 Views 폴더로 이동하여 Web.config 파일을 찾는 것입니다. 이제 <namespaces>태그를 찾아 확장 네임 스페이스를 다음과 같이 추가하십시오.

<add namespace="App.Extensions" />

파일을 저장하면 완료됩니다. 이제 모든 View는 확장을 알고 있습니다.

확장 방법에 액세스 할 수 있습니다.

var orgId = User.Identity.GetOrganizationId();

파블 안녕하세요,이 같은 시도하지만, 오류가 발생하면 응용 프로그램 사용자가 OrganisationId의 정의를 포함하지 않습니다
그것은 함정

@RachitGupta 언제 발생합니까? 클레임을 추가하려고 할 때나 나중에 코드에서 해당 값에 액세스하려고 할 때? 클레임을 추가하는 경우 ApplicationUser에 속성이 정의되어 있는지 확인하십시오. 코드의 후반부에 다음과 같이 확장 메소드를 작성한 위치에 using 문을 추가하는 것을 잊지 마십시오. using App.Extensions ;
Pawel

userIdentity.AddClaim 줄에 오류가 있습니다. IdentityModels.cs 파일에서만 IdentityExtensions 클래스를 만들었습니다. 이것이 문제의 원인이 될 수 있습니까?
그것은 함정이다

아니요, 소유권 주장을 추가 할 때 identityExtensions가 실행되기 전에 발생합니다 (값을 다시 읽을 때) ... ApplicationUser에 소유권 주장으로 추가하려는 속성이 있는지 확인하십시오.이 예에서는 공공 장소 OrganizationId {get; 세트; }
Pawel

6
고마워요 이것이 Asp Net Idendity 2의 사용자 정의 변수에 대한 모범 사례라고 생각합니다. Asp.Net 커뮤니티가 웹 사이트의 기본 기사에서 이러한 예제를 제공하지 않는 이유를 모르겠습니다.
oneNiceFriend 2016 년

17

나는 같은 해결책을 찾고 있었고 Pawel은 99 %의 대답을 주었다. 확장 프로그램을 표시하는 데 필요한 유일한 것은 cshtml (view) 페이지에 다음 Razor Code를 추가하는 것입니다.

@using programname.Models.Extensions

사용자가 로그인 한 후 NavBar의 오른쪽 상단에 표시 할 FirstName을 찾고있었습니다.

다른 사람을 돕기 위해이 게시물을 게시 할 것이라고 생각했습니다. 그래서 내 코드는 다음과 같습니다.

Extensions (내 모델 폴더 아래)라는 새 폴더를 만들고 위에서 지정한 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.cshtml아래에 Views/Shared추가했습니다.@using.ProgramName.Models.Extensions

그런 다음 로그인 후 사용자 이름을 사용하려는 다음 코드 줄에 변경 사항을 추가했습니다.

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

아마도 이것은 다른 사람이 도움을 줄 수 있습니다.


11

John Atten이 작성한이 훌륭한 블로그 게시물을 확인하십시오. ASP.NET Identity 2.0 : 사용자 및 역할 사용자 정의

전체 프로세스에 대한 훌륭한 단계별 정보가 있습니다. 읽어보세요 :)

다음은 몇 가지 기본 사항입니다.

새로운 속성 (주소, 도시, 주 등)을 추가하여 기본 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; }

그런 다음 등록 정보를 업데이트하여 새 속성을 포함시킵니다.

    <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;

16
이것은 좋은 예이지만 User.Identity에서 새로운 속성을 얻는 방법에 대한 대답은 아닙니다.
Dejan Bogatinovski

5
답변에 User.Identity에서 사용자 지정 속성을 검색하는 방법이 표시되지 않기 때문에 하향 조정되었습니다.
maulik13

3

ASP.NET Core 2.1에서 사용자 지정 속성에 액세스하는 방법을 찾는이 질문을 찾는 사람에게는 훨씬 쉽습니다. 예를 들어 _LoginPartial.cshtml과 같은 UserManager가 있고 간단하게 수행 할 수 있습니다 ( "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
주목해야한다 GetUserAsync(User)OrganizationId를 검색 할 수있는 데이터베이스를 조회합니다. 반대로, 허용 된 솔루션에는 클레임 ​​(예 : 쿠키)에 OrganizationId가 포함됩니다. 데이터베이스에서이 정보를 가져 오는 이점은 사람들이 로그 아웃 / 로그인하지 않고도 조직간에 이동할 수 있다는 것입니다. 물론 추가적인 데이터베이스 쿼리가 필요하다는 단점이 있습니다.
Matt

1

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;

0

또한 AspNetUsers 테이블에 열을 추가하거나 확장했습니다. 이 데이터를 단순히보고 싶을 때 "Extensions"등을 사용하여 위의 코드와 같은 많은 예제를 찾았습니다. 이것은 현재 사용자로부터 몇 가지 값을 얻기 위해 모든 코드 줄을 작성해야한다는 사실에 놀랐습니다.

다른 테이블과 마찬가지로 AspNetUsers 테이블을 쿼리 할 수 ​​있습니다.

 ApplicationDbContext db = new ApplicationDbContext();
 var user = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.