ASP.NET Identity не загружает никаких утверждений

У меня есть сайт ASP MVC 5, использующий новую структуру идентификации со сторонней аутентификацией с использованием структуры сущностей, которая поставляется из коробки. У меня есть зарегистрированный пользователь, и у него есть 3 утверждения (стандартный идентификатор имени и провайдер аутентификации, которые, по-видимому, предоставляются по умолчанию ClaimsIdentityFactory).

Когда пользователь выполняет какую-либо операцию, я добавляю для него заявку, используя это:

userManager.AddClaim(userId, new Claim(claimType,claimValue));

Если я посмотрю в базу данных в таблице AspNetUserClaims, то увижу строку для моего нового утверждения. Большой.

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

Моя первоначальная проблема, я думал, заключалась в том, что вошедший в систему пользователь никогда не обновлял свой файл cookie, чтобы содержать новое утверждение, поэтому я вышел из системы, думая, что, когда они снова войдут в структуру, прочитают утверждения и создадут новые утверждения для пользователя, и тогда они будут в куки. Но мне должно быть что-то не хватает, потому что даже когда мой пользователь снова входит в систему, у него нет претензии.

Фактически, если я регистрирую активность БД, когда эта строка вызывается в ExternalLoginCallback:

// Sign in the user with this external login provider if the user already has a login
ApplicationUser user = await UserManager.FindAsync(loginInfo.Login);

я получаю вот что:

iisexpress.exe' (CLR v4.0.30319: /LM/W3SVC/2/ROOT-2-130416316906840516): Loaded 

'EntityFrameworkDynamicProxies-Microsoft.AspNet.Identity.EntityFramework'. 
SELECT TOP (1) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name]
    FROM [dbo].[AspNetRoles] AS [Extent1]
    WHERE (((UPPER([Extent1].[Name])) = (UPPER(@p__linq__0))) AND ( NOT ((UPPER([Extent1].[Name]) IS NULL) OR (UPPER(@p__linq__0) IS NULL)))) OR ((UPPER([Extent1].[Name]) IS NULL) AND (UPPER(@p__linq__0) IS NULL))


-- p__linq__0: 'TeamManagement' (Type = String, Size = -1)

-- Executing at 10/04/2014 20:28:29 +01:00

-- Completed in 2 ms with result: GlimpseDbDataReader



'iisexpress.exe' (CLR v4.0.30319: /LM/W3SVC/2/ROOT-2-130416316906840516): Loaded 'EntityFrameworkDynamicProxies-Haccapp.Model'. 
SELECT 
    [Extent1].[Discriminator] AS [Discriminator], 
    [Extent1].[Id] AS [Id], 
    [Extent1].[UserName] AS [UserName], 
    [Extent1].[PasswordHash] AS [PasswordHash], 
    [Extent1].[SecurityStamp] AS [SecurityStamp], 
    [Extent1].[PreferredEmailAddress] AS [PreferredEmailAddress]
    FROM [dbo].[AspNetUsers] AS [Extent1]
    WHERE ([Extent1].[Discriminator] IN (N'ApplicationUser',N'IdentityUser')) AND ([Extent1].[Id] = @p0)


-- p0: 'SiteOwner' (Type = String, Size = -1)

-- Executing asynchronously at 10/04/2014 20:28:29 +01:00

GlimpseDbCommand.TimerStrategy is null
-- Completed in 6 ms with result: GlimpseDbDataReader



SELECT 
    [Limit1].[Discriminator] AS [Discriminator], 
    [Limit1].[Id] AS [Id], 
    [Limit1].[UserName] AS [UserName], 
    [Limit1].[PasswordHash] AS [PasswordHash], 
    [Limit1].[SecurityStamp] AS [SecurityStamp], 
    [Limit1].[PreferredEmailAddress] AS [PreferredEmailAddress]
    FROM ( SELECT TOP (1) 
        [Extent2].[Id] AS [Id], 
        [Extent2].[UserName] AS [UserName], 
        [Extent2].[PasswordHash] AS [PasswordHash], 
        [Extent2].[SecurityStamp] AS [SecurityStamp], 
        [Extent2].[PreferredEmailAddress] AS [PreferredEmailAddress], 
        [Extent2].[Discriminator] AS [Discriminator]
        FROM  [dbo].[AspNetUserLogins] AS [Extent1]
        LEFT OUTER JOIN [dbo].[AspNetUsers] AS [Extent2] ON ([Extent2].[Discriminator] IN (N'ApplicationUser',N'IdentityUser')) AND ([Extent1].[UserId] = [Extent2].[Id])
        WHERE ([Extent1].[LoginProvider] = @p__linq__0) AND (@p__linq__0 IS NOT NULL) AND ([Extent1].[ProviderKey] = @p__linq__1) AND (@p__linq__1 IS NOT NULL)
    )  AS [Limit1]


-- p__linq__0: 'Google' (Type = String, Size = -1)

-- p__linq__1: 'https://www.google.com/accounts/o8/id?id=some_account_id' (Type = String, Size = -1)

-- Executing asynchronously at 10/04/2014 20:28:29 +01:00

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

Затем код делает следующее:

ClaimsIdentity identity = await UserManager.CreateIdentityAsync(user, defaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties {IsPersistent = isPersistent}, identity);

и тогда личность имеет 3 утверждения.

Что мне нужно сделать, чтобы утверждения загружались из базы данных при загрузке своего пользователя? И как только я это сделаю, что мне нужно сделать, чтобы все новые претензии, которые мой пользователь получает во время использования сайта, обновлялись в пользовательских файлах cookie?

Я чувствую, что мне здесь не хватает чего-то фундаментального.

ИЗМЕНИТЬ

Так что я немного поигрался с этим и в итоге реализовал свой собственный ClaimsIdentityFactory вот так:

public class FullyLoadingClaimsIdentityFactory : ClaimsIdentityFactory<ApplicationUser>
{
    private readonly ApplicationDb db;

    public FullyLoadingClaimsIdentityFactory(ApplicationDb db)
    {
        this.db = db;
    }

    public override async Task<ClaimsIdentity> CreateAsync(UserManager<ApplicationUser> manager, ApplicationUser user, string authenticationType)
    {
        var currentClaims = db.UserClaims.Where(x => x.User.Id == user.Id).ToList();
        var claimsIdentity = await base.CreateAsync(manager, user, authenticationType);
        claimsIdentity.AddClaims(currentClaims.Select(c=>new Claim(c.ClaimType,c.ClaimValue)));
        return claimsIdentity;
    }
}

Теперь это явно запрашивает базу данных для загрузки пользовательских утверждений. Мне пришлось добавить свойство к моему классу, производное от IdentityDbContext, чтобы я мог раскрыть объекты IdentityUserClaim фреймворка:

 public IDbSet<IdentityUserClaim> UserClaims { get; set; }

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

Кроме тех случаев, когда я звоню:

var claimsIdentity = await base.CreateAsync(manager, user, authenticationType);

он также загружает мои утверждения, что раньше он не загружался.

на самом деле, если я перейду на это:

var claimsIdentity = await base.CreateAsync(manager, user, authenticationType);
Trace.WriteLine(claimsIdentity.Claims.Count()); <-- traces 3
var currentClaims = db.UserClaims.Where(x => x.User.Id == user.Id).ToList();
claimsIdentity = await base.CreateAsync(manager, user, authenticationType);
Trace.WriteLine(claimsIdentity.Claims.Count());  <-- traces 6!

тогда я не получаю утверждения в БД (из которых 3) загружаются, когда я впервые создаю ClaimsIdentity, но во второй раз я создаю удостоверение после того, как я вручную запросил БД, претензии есть.

Почему это могло быть? Теперь я чувствую, что это связано с EF, но не знаю, почему ...


person Sam Holder    schedule 10.04.2014    source источник
comment
Я не уверен, но попробуйте просмотреть msdn.microsoft .com / en-us / library / hh291061 (v = vs.110) .aspx и brockallen.com/2012/07/08/mvc-4-antiforgerytoken-and-claims   -  person DmitryBoyko    schedule 11.04.2014
comment
@ClarkKent, спасибо, но они оба, похоже, говорят о более старых реализациях в основном с WIF. Кажется, что мне нужно реализовать свой собственный ClaimsIdentityFactory и вручную загрузить туда утверждения из UserManager, но это кажется всевозможным или неправильным.   -  person Sam Holder    schedule 11.04.2014


Ответы (1)


Да, это была ошибка, которую следует исправить при обновлении до версии 2.0. В основном вы хотите убедиться, что LazyLoading включена, дополнительную информацию можно найти здесь

person Hao Kung    schedule 10.04.2014
comment
Спасибо. 3 часа моей жизни я не вернусь. Но по крайней мере сейчас их всего 3 :-). - person Sam Holder; 14.04.2014
comment
Я знаю, что опаздываю на вечеринку, но версия 2 чего? У меня только что было это с EF v6, MVC v5, Identity Core v2? - person bicbmx; 23.04.2018
comment
он не работает с aspnet.core v2.2 и ef core 2.2.6 - person Illia; 30.03.2020