Toon posts:

[ASP.NET Identity] HttpContext.Current is null

Pagina: 1
Acties:

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 25-03 15:52
Introductie
Ik bouw een custom implementatie van Identity 2.0. Standaard refresht het framework de identity van de ingelogde user elke 30 minuten, door een nieuwe ClaimsIdentity aan te maken. Omdat ik een aantal custom claims heb (die ik tijdens het inloggen set) wil ik deze claims overhevelen naar de nieuwe ClaimsIdentity wanneer die gerefreshed wordt. Daarvoor heb ik een manier bedacht die de huidige ClaimsIdentity uit de HttpContext leest en die teruggeeft als een nieuwe ClaimsIdentity in the RegenerateIdentity method. Het probleem is echter dat HttpContext.Current null is tijdens dat proces, dus ik kan m'n huidige claims niet overhevelen.

De code
In mijn startup.cs file heb ik deze code die de gebruiker zijn identity elke 0.5 minuut refresht:

C#:
1
2
3
4
5
6
7
8
9
10
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    Provider = new CookieAuthenticationProvider
    {
        OnValidateIdentity = SecurityStampValidatorExtensions.OnValidateIdentity(
            validateInterval: TimeSpan.FromMinutes(0.5),
            regenerateIdentity: (manager, user) => manager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie))
    }
});


De RegenerateIdentity Func roept deze method aan in mijn UserManager:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public async override Task<ClaimsIdentity> CreateIdentityAsync(ApplicationUser user, string authenticationType)
{
    ClaimsIdentity claimsIdentity;
    if (HttpContext.Current != null && 
        HttpContext.Current.User != null && 
        HttpContext.Current.User.Identity != null && 
        HttpContext.Current.User.Identity.IsAuthenticated)
    {
        // Just return the existing ClaimsIdentity so we don't lose our custom claims
        claimsIdentity = (ClaimsIdentity)HttpContext.Current.User.Identity;

        // TODO refresh some claims from the database

        return claimsIdentity;
    }

    // Create a new ClaimsIdentity if none exists
    claimsIdentity = await ClaimsIdentityFactory.CreateAsync(this, user, authenticationType);
    claimsIdentity.AddClaim(new Claim(Constants.DefaultSecurityStampClaimType, await GetSecurityStampAsync(user.Id)));

    return claimsIdentity;
}


Het probleem
De eerste keer dat ik inlog wordt CreateIdentityAsync aangeroepen. HttpContext.Current heeft dan gewoon een waarde en de identity wordt netjes aangemaakt. Wanneer CreateIdentityAsync echter nog een keer wordt aangeroepen (omdat de identity wordt gerefreshed) is HttpContext.Current null. Ik snap niet echt waar het fout gaat.

Mijn theorieën
  • Misschien wordt er door async iets op een andere thread uitgevoerd die geen beschikking heeft over de HttpContext? Ik heb een eigen awaiter geschreven om de HttpContext te kopiëren maar dat hielp niet, omdat de HttpContext kennelijk al leeg is in UseCookieAuthentication method van de startup.cs.
  • De HttpContext bestaat nog niet of bestond wel maar is vernietigd door ASP.NET MVC of iets dergelijks? Niks kunnen vinden wat daar op duidt.
Oplossingen die ik zelf heb bedacht (maar die niet werken)
  • De custom claims in de database op slaan. Ik sla ze echter liever niet op in de database. Ook gaat dat denk ik niet goed met expiration? In principe moeten de custom claims gebonden zijn aan een sessie en daarna expiren.
  • De claims cachen in een in-memory cache. Het probleem daarbij is hetzelfde als bij het vorige punt: de claim moet niet alleen geassocieerd zijn met een user, maar ook met een sessie. Omdat je sessie ook opgevraagd wordt via de HttpContext gaat dat ook niet werken.
  • De HttpContext over proberen te hevelen met een custom awaiter, maar dat werkt niet omdat de HttpContext in eerste instantie al leeg was.
  • Aangezien van de ClaimIdentity een User object wordt gemaakt (je IUser<T> implementatie die door je store/manager wordt gebruikt) lijkt me dat je je claims ook over kunt hevelen naar dat User object. Ik heb echter geen idee hoe/waar ik dat zou moeten doen en of het gaat werken. Dat zou wel een mooie oplossing zijn; dan heb je overal waar je een User object hebt ook meteen je claims, zonder dat je die elke keer uit je ClaimsIdentity hoeft te halen.
Wie helpt mij verder?

  • GrooV
  • Registratie: September 2004
  • Laatst online: 24-03 15:45
Volgens mij zit HttpContext.Current niet meer in de nieuwe HttpContext

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 25-03 15:52
Huh? Waar heb je het over?

  • GrooV
  • Registratie: September 2004
  • Laatst online: 24-03 15:45
Welke MVC versie gebruik je?

[Voor 14% gewijzigd door GrooV op 03-12-2014 20:39]


  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 25-03 15:52
MVC 5 (of 5.1 / 5.2) met .NET 4.5.1.

  • GrooV
  • Registratie: September 2004
  • Laatst online: 24-03 15:45
Ik heb niet helemaal door wat je nu precies probeert te doen maar goed. Je HttpContext is niet meer beschikbaar zodra je buiten de asp pipeline gaat. Dit komt omdat je een nieuwe async thread aanmaakt die niet meer bij de httpcontext kan.

Kijk hier eens naar http://benfoster.io/blog/...-stripped-bare-mvc-part-1

En mijn eerste post sloeg op de nieuwe ASP.NET die geen HttpContext.Current meer heeft, zie https://github.com/aspnet...spNet.Http/HttpContext.cs

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 25-03 15:52
GrooV schreef op woensdag 03 december 2014 @ 20:48:
Ik heb niet helemaal door wat je nu precies probeert te doen maar goed. Je HttpContext is niet meer beschikbaar zodra je buiten de asp pipeline gaat. Dit komt omdat je een nieuwe async thread aanmaakt die niet meer bij de httpcontext kan.
Ik probeer gewoon de claims in mijn identity object over te hengelen naar een nieuw identity object. Je identity object wordt namelijk elke x minuten ververst door het framework.
Ik zie daar niks wat te maken heeft met mijn probleem.
En mijn eerste post sloeg op de nieuwe ASP.NET die geen HttpContext.Current meer heeft, zie https://github.com/aspnet...spNet.Http/HttpContext.cs
Daar ben ik van op de hoogte, maar ik gebruik geen vNext. Dit gaat om een productie-applicatie (die ik natuurlijk niet ga baseren op een betaproduct). Dat viel ook wel af te leiden uit m'n topicstart aangezien ik spreek over Identity 2.0. vNext gebruikt 3.0 :)

  • DoDo
  • Registratie: Juli 2001
  • Laatst online: 13:29
Avalaxy schreef op woensdag 03 december 2014 @ 20:51:
[...]


Ik probeer gewoon de claims in mijn identity object over te hengelen naar een nieuw identity object. Je identity object wordt namelijk elke x minuten ververst door het framework.


[...]


Ik zie daar niks wat te maken heeft met mijn probleem.


[...]


Daar ben ik van op de hoogte, maar ik gebruik geen vNext. Dit gaat om een productie-applicatie (die ik natuurlijk niet ga baseren op een betaproduct). Dat viel ook wel af te leiden uit m'n topicstart aangezien ik spreek over Identity 2.0. vNext gebruikt 3.0 :)
Zoals GrooV al heeft aangegeven heb je geen HttpContext meer in je async methode. Je kan de HttpContext meegegeven als parameter aan deze methode, maar beter nog maak je gebruik van SynchronizationContext.

Zie ook de volgende links:
http://stackoverflow.com/...angerous-because-of-async
MSDN: MSDN Magazine: Parallel Computing - It's All About the SynchronizationContext

[Voor 10% gewijzigd door DoDo op 04-12-2014 12:28]


  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 25-03 15:52
Hmm, wat moet ik concreet veranderen aan mijn code dan?

  • Avalaxy
  • Registratie: Juni 2006
  • Laatst online: 25-03 15:52
Ik heb het nu even anders opgelost:

Ik heb mijn user object (ApplicationUser) een collectie van claims gegeven. Vervolgens ben ik in de code van OnValidateIdentity gedoken en hier een kopie van gemaakt (helaas, is een static method). In die OnValidateIdentity method kun je via context.Identity je bestaande claimsidentity ophalen, waarna een user object wordt aangemaakt. Daar kopieer ik dus mijn claims naar mijn user object, die weer naar de CreateIdentityAsync method worden gepassed. Daar kan ik ze vervolgens gewoon overkopiëren naar m'n nieuwe claimsidentity object.

Niet echt netjes, aangezien ik een copy+pasta+aanpassing heb gedaan van de interne Identity code, maar het is vooralsnog de enige oplossing die werkt.
Pagina: 1


Tweakers maakt gebruik van cookies

Tweakers plaatst functionele en analytische cookies voor het functioneren van de website en het verbeteren van de website-ervaring. Deze cookies zijn noodzakelijk. Om op Tweakers relevantere advertenties te tonen en om ingesloten content van derden te tonen (bijvoorbeeld video's), vragen we je toestemming. Via ingesloten content kunnen derde partijen diensten leveren en verbeteren, bezoekersstatistieken bijhouden, gepersonaliseerde content tonen, gerichte advertenties tonen en gebruikersprofielen opbouwen. Hiervoor worden apparaatgegevens, IP-adres, geolocatie en surfgedrag vastgelegd.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Toestemming beheren

Hieronder kun je per doeleinde of partij toestemming geven of intrekken. Meer informatie vind je in ons cookiebeleid.

Functioneel en analytisch

Deze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring. Klik op het informatie-icoon voor meer informatie. Meer details

janee

    Relevantere advertenties

    Dit beperkt het aantal keer dat dezelfde advertentie getoond wordt (frequency capping) en maakt het mogelijk om binnen Tweakers contextuele advertenties te tonen op basis van pagina's die je hebt bezocht. Meer details

    Tweakers genereert een willekeurige unieke code als identifier. Deze data wordt niet gedeeld met adverteerders of andere derde partijen en je kunt niet buiten Tweakers gevolgd worden. Indien je bent ingelogd, wordt deze identifier gekoppeld aan je account. Indien je niet bent ingelogd, wordt deze identifier gekoppeld aan je sessie die maximaal 4 maanden actief blijft. Je kunt deze toestemming te allen tijde intrekken.

    Ingesloten content van derden

    Deze cookies kunnen door derde partijen geplaatst worden via ingesloten content. Klik op het informatie-icoon voor meer informatie over de verwerkingsdoeleinden. Meer details

    janee