The original motivation for this article is about following issue:
- how does the claim identity information persist after login in ASP.NET
- why does updating of claim identity in owin context not persist in further request
WIF(Windows Identity Foundation) provides a Claims-Based Identity Model. And in
ASP.NET, we can already build a Claims-Aware ASP.NET Web Application. Especially, when using with different kind of authentication middleware,
WIF provides the same abstract layer to access the identity information across the whole asp.net pipeline context.
In this article we will talk about some detail about asp.net authentication middleware based on the
CookieAuthenticationMiddleware. At the end, let’s discuss more about persist claim in cookie across request.
Simple speaking, Owin pipeline is a link of middleware, and the request will dive into this link to the end(or short-circuited before end), and the response will pop up back though the pipeline middleware. When coming through the middleware, this gives opportunity to middleware to process and even short-circuit the whole process line.
Request /=====\ /=====\ /=====\ =====> | | =====> | | =====> | | | MW1 | | MW2 | | MW3 | <===== | | <===== | | <===== | | <== Response \=====/ \=====/ \=====/
This diagram is a very simple and straightforward explanation about the Owin Middleware.
And authentication middleware if one kind of middleware that will give their effect to the request and response process.
Here is the definition the
OwinMiddleware, there is two key pieces in code:
- next: reference to the next middleware in pipeline
Invokeabstract function: this is the how this middleware could perform on the owin conext. The usually pattern would be “Before action” + “next.Invoke()” + “after action”.
AuthenticationMiddleware is the base class for all authentication middleware. And it implement the basic pattern for the
Invoke function for a concrete authentication middleware. Here is the flow:
And more detail code is as below:
So we can see that, the concrete authentication middleware will create an authentication handler and use that handler for further processing. The main logic for a authentication middleware is mainly about how the handler is implemented.
So let’s see the peice of code for
So the main logic of authentication middleware will be focus on authentication handler. Let see a deeper graph when we expand the
The blue part will be the main part of how
AuthenticationHandler works. And the red part will be how a specific authentication handler, here is
We do not have the plan to dive into every detail of how CookieAuthenticationHandler implemented. So we only focus to original issue, how claim identity does the persistence underlying.
In fact, originally, i thought the claim identity which we can access via
User.Identity will be persist in cookie. So if I update the claims in
User context, everything will be persist ( i mean update ) into the cookie later. So I can access the updated value in later request.
However, the thing is not as I wish.
Here is the expanded version for
TeardownAsync will perform the persistence logic from the identity, but not like we wish. From the diagram, we found that findally, the
CookieAuthenticationHandler use the
ApplyResponseGrantAsync to save information. And what is
We can refer to more detail from the implementation:
From the code, two things need to pay attention to:
- the handler will save the
- the action in step 1 will only happen when we can have this
Ok, let’s find the final piece about this
So we finally found where the data comes from - Authentication.AuthenticationResponseGrant.
Grant is the concept of the information that we retreive after we do the authentication. If the cookie handler save this grant into the cookie, we need to find where is grant come from.
So in fact, this
grant information is set when we call the
SignIn function of the authenticaton manager. And if we do not call
SignIn, the AuthenticationResponseGrant will be null. In that case, the cookie will not be updated.
User.Identity will NOT set to this authentication grant if
SignIn is not called. That is why even update the
User.Identity but those updated information will not take effect for any further request in asp.net.
This is also explain every detail about this stackoverflow question Persisting claims across requests
After dive into such more detail from code level, let’s discuss about the original topic.
I found a solution here from the stackoverflow How to update a claim in ASP.NET Identity?, this solution will set the
AuthenticationResponseGrant explicitly when try to update the claim items, this will trigger the sign in logic when
Teardown is called.
In fact, this is one of the solution that indeed take effect. But it has a potential issue, that is, in fact, such kind of code will trigger the sign in logic underlying, and the sign in logic will update the cookie expiration time. This behavior works as you sigin in again when you explicitly set the
AuthenticationResponseGrant. Of course, if the cookie expiration time is not a problem for your business logic, espeically when you use the SlidingExpiration, everyting should be fine.
But for my business which use the cookie authentication expiration as the web application login expiration. This will be a problem, and i should not use this way to update claim information in cookie.
So based on the implementation of Katana( i do not read the latest code, so correct me if i miss something), the identity saved in cookie is not designed for dynamically update. Those claim identity in the cookie is represented as a unique identity information that binding to a specific login and it should be immutable. And, updating the claim data in cookie with
AuthenticationResponseGrant means to a totally new login instead of updating the current login context. So all the claim data that is persisted in the cookie should not be updated within a specific login session. So that is why we can found that most of the authenticaton middleware save the claim identity information belong to the login itself to the cookie.
Yes, you may say that, how about those that do not belong to so-called “login information”, where should I save it? In fact, within asp.net project template the microsoft already provide us the way when you select “Individual Use Account”.
I do not want to dive more code here, the magic is
ApplicationUserManager. This manager is using
UserStore binding to a entityframework
DbContext object. We can use the user manager’s
RemoveClaimAsync to manipulate the claim data we want to save. The user manager will sync those saved claim everytime when the next query is comming, like what we wish. And yes, i think you already guess the conclusion, user manager is using the database to save the claim identity information underlying.
And one more option, if you just want to save some data between request, and those information is not a sensitive data, such as access code, you can use the
Request.Cookie directly, and you can see those data from chrome debug panel under
Resource tab directly. More simple, right?
Ok, claim identity in asp.net is so a big topic so i would talk more aspect on other article, let’s end here.
Any question, please just reply and discuss with me :-)
- Persisting claims across requests
- Server side claims caching with Owin Authentication
- How to update a claim in ASP.NET Identity?
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Please refer to the auther's name `winterTTr` when you remix, transform, and build upon this material.
winterTTr创作，采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。修改，参照或者转载请注明作者