Как расширить доступные свойства User.Identity

Я использую MVC5 Identity 2.0 для входа на мой сайт, где данные аутентификации хранятся в базе данных SQL. Идентификация Asp.net была реализована стандартным способом, как это можно найти во многих онлайн-учебниках.

Класс ApplicationUser в IdentityModels был расширен, чтобы включить некоторые настраиваемые свойства, такие как целое 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 текущего зарегистрированного пользователя из контроллера? Доступно ли это через метод, когда пользователь вошел в систему или всегда ли я получаю OrganizationId из базы данных на основе UserId, каждый раз, когда выполняется метод контроллера?

Чтение в Интернете, которое я видел, мне нужно использовать следующее, чтобы получить вход в UserId и т.д.

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

Однако OrganizationId не является свойством, доступным в User.Identity. Нужно ли расширять User.Identity, чтобы включить свойство OrganizationId? Если да, то как это сделать.

Причина, по которой мне нужна организацияId так часто, заключается в том, что многие запросы в таблице зависят от OrganizationId для извлечения данных, относящихся к Организации, связанных с зарегистрированным пользователем.

Ответ 1

Всякий раз, когда вы хотите расширить свойства 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;
        }
    }
}

Когда вы создаете Identity в классе 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; внутри контроллера и @using. App.Extensions с файлом View.cshtml View.

ИЗМЕНИТЬ:

Что вы также можете сделать, чтобы избежать добавления оператора using в каждом представлении, это перейти в папку "Представления" и найти там файл Web.config. Теперь найдите тег и добавьте пространство имен расширения так:

<add namespace="App.Extensions">

Сохраните файл, и все готово. Теперь каждый вид будет знать ваши расширения.

Вы можете получить доступ к методу расширения:

var orgId = User.Identity.GetOrganizationId();

Надеюсь, что кто-нибудь поможет:)

Ответ 2

Я искал то же решение, и Павел дал мне 99% ответа. Единственное, чего не хватало для расширения для отображения, было добавление следующего кода Razor на страницу cshtml (view):

@using programname.Models.Extensions

Я искал FirstName, чтобы отобразить его в правом верхнем углу моего NavBar после входа пользователя.

Я думал, что я опубликую это сообщение, это поможет кому-то другому. Итак, вот мой код:

Я создал новую папку под названием 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.cshtmlViews/Shared Folders) я добавил @using.ProgramName.Models.Extensions

Затем я добавил изменение в строку вывода кода, которая будет использовать имя пользователя First после входа в систему:

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

Возможно, это помогает кому-то еще по очереди.

Ответ 3

Посмотрите это замечательное сообщение в блоге от 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>

Затем обновите метод Register() на AccountController с новыми свойствами.

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

Ответ 4

DULT дает хороший способ добавить свойство в класс ApplicationUser. Глядя на код OP, похоже, они, возможно, сделали это или были на пути к этому. Вопрос задает

Как я могу получить свойство OrganizationId текущего зарегистрированного пользователя из контроллера? Однако OrganizationId не является свойством, доступным в User.Identity. Мне нужно расширить User.Identity, чтобы включить свойство OrganizationId?

Pawel дает возможность добавить метод расширения, который требует использования операторов или добавления пространства имен в файл web.config.

Однако вопрос задает вопрос, нужно ли вам "расширить" User.Identity, чтобы включить новое свойство. Существует альтернативный способ доступа к объекту без расширения User.Identity. Если вы воспользовались методом DULT, вы можете использовать следующий код в своем контроллере для доступа к новому свойству.

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