Your official information source from the .NET Web Development and Tools group at Microsoft.
The new security feature design for MVC 5 is based on OWIN authentication middleware. The benefit for it is that security feature can be shared by other components that can be hosted on OWIN. Since the Katana team did a great effort to support the OWIN integrated pipeline in ASP.NET, it can also secure apps hosted on IIS, including ASP.NET MVC, Web API, Web Form.
Forms authentication uses an application ticket that represents user's identity and keeps it inside user agent's cookie. When user first accesses a resource requiring authorization, it will redirect user to login page. After the user provides credentials, your application code will validate the user name and password and build user claims including user's name, roles, etc. After passing claims to the Forms authentication middleware, it will convert it to an application ticket and serialize, encrypt and encode it into a ticket token. Then, send it out as a cookie. When the next time user sends request with the cookie, the middleware will validate it and convert the ticket token back to claims principal and save it in HttpContext.User, which will shared across ASP.NET pipeline.
ASP.NET also has a forms authentication support through the FormsAuthenticationModule, which, however, can only support applications hosted on ASP.NET and doesn't have claim support . Here is a rough feature comparison list:
Features
Asp.Net Forms Authentication
OWIN Forms Authentication
Cookie Authentication
Yes
Cookieless Authentication
No
Expiration
Sliding Expiration
Token Protection
Claims Support
Web Farm Support
Unauthorized Redirection
In this blog, you will learn:
· Creating an MVC project with OWIN Forms authentication enabled.
· Understanding OWIN Forms authentication options.
· Understanding Application Sign In Cookie flow.
· Understanding External Sign In Cookie flow.
· Working with new Identity API
To get started, you need to create new MVC .
· Make sure you have installed:
· In Visual Studio 2013, select New Project from File menu
· In New Project dialog, select Installed Template / Visual C# / Web / ASP.NET Web Application
· In New ASP.NET Project dialog, select MVC project template
Optional: On the right panel of the dialog, you can select Configure Authentication, to choose No Authentication, Individual User Accounts, Organization Authentication and Windows Authentication. In this tutorial, we use Individual User Accounts, which is the default setting.
· Click Create Project button
In the new project, open the App_Start/Startup.Auth.cs file. It has the following code:
Note that UseSignInCookies must be called before any external login providers.
The UseSignInCookies extension method actually registers two cookie authentications. (You can see the source for the methods below at at: http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Forms/FormsAuthenticationExtensions.cs )
Both the UseApplicationSignInCookie and the UseExternalSignInCookie extension methods call UseFormsAuthentication, but with different settings.
The Application sign in cookie is used to authenticate users for the current application, while external sign in cookie is used to authenticate users from external providers, like Facebook, Google, Twitter and Microsoft account. If you want to change the default authentication options, you can use UseFormsAuthentication extension method to change them.
Here are list of options that you can change in UseFormsAuthentication:
Options
Description
ApplicaitonSignInCookie Default Values
ExternalSignInCookie Default Values
AuthenticationMode
If Active the authentication middleware alters the requested user coming in and returns 401 Unauthorized responses going out.
If Passive the authentication middleware will only provide identity and alter responses when explicitly indicated by the AuthenticationType.
Active
Passive
AuthenticationType
The AuthenticationType in the options corresponds to the IIdentity.AuthenticationType property. A different value may be assigned in order to use the same authentication middleware type more than once in a pipeline.
“Application”
“External”
CookieDomain
Defines the domain that cookie is under
<null>
CookieHttpOnly
Defines if the cookie is http only. It's true by default.
True
CookieName
Defines the name of the cookie
“.AspNet.Application”
“.AspNet.External”
CookiePath
Defines the path that cookie is under. By default, it's /.
“/”
CookieSecure
Defines if the cookie will only be sent back to HTTPS URL. By default, it is SameAsRequest, which means If the URI that provides the cookie is HTTPS, then the cookie will only be returned to the server on subsequent HTTPS requests. Otherwise if the URI that provides the cookie is HTTP, then the cookie will be returned to the server on all HTTP and HTTPS requests.
SameAsRequest
ExpireTimeSpan
Defines the expiration of the cookie.
14 days
5 minutes
LoginPath
Defines the Login path when unauthorized request will be redirected to.
“/Account/Login”
ReturnUrlParameter
Defines the return URL parameter name, which tells your application the URL of previous unauthorized request to redirect to after login. Your application code is responsible for retrieving it and redirecting the user agent to the return URL
“ReturnUrl”
SlidingExpiration
Defines if the authentication supports sliding expiration, which will automatically extends the expiration time if user session is still active. By default, it's true.
False
Provider
The forms authentication provider that can intercept events during sign in and validate identity.
· OnResponseSignin: happens just before set-cookie is sent out
· OnValidateIdentity: happens just after incoming cookie is parsed into ClaimsIdentity
Active mode is similar to what the old ASP.NET forms authentication module did, while passive is a way to let framework code control the authentication explicitly.
ApplicatinSignInCookie is an active forms authentication middleware, so when a valid cookie is returned, it will:
· Automatically redirect an unauthorized response to the login page.
· Set the logged in user principal to HttpContext.User, so the rest of ASP.NET pipeline will know what user is authenticated.
The following is a basic flow of application forms authentication.
User Agent
Forms Authentication Middleware(Application)
Web App
1. Get /Account/Manage
---------------------------->
2. Response Status: 401
AccountController is protected by Authroize attribute, so unauthorized request will return a 401 error.
[Authorize]
public class AccountController : Controller
{
}
<----------------------------
3. Alter response status to 302 and redirect to /Application/Login?ReturnUrl=/Account/Manage
The application sign in cookie is in active authentication mode and it will automatically redirect to login page when there is a 401 response.
4. GET /Application/Login?ReturnUrl=/Account/Manage
5. Response Status: 200 and with login page in body
6. POST /Application/Login?ReturnUrl=/Account/Manage
User input user name and password and post back to server
7. Status: 301
Location: /Account/Manage
Server code does:
a. Validating user credentials
b. Calling IdentityAuthenticationManager.SignIn to sign in with application sign in cookie
c. Redirecting to returnUrl
8. Status: 302
Set-Cookie: .AspNet.Application=<Ticket Token>
The middleware will convert user claims with extra data into ticket token and set it in cookie.
9. GET /Account/Manage
Cookie: .AspNet.Application=<Ticket Token>
10. Validate <Ticket Token> and convert it to claims identity and set it to HttpContext.User
11. Status: 200 with manage account page in body
Authorize attribute sees that the identity is authenticated from HttpContext.User. So allow the request to reach the action.
ExternalSignInCookie is a passive forms authentication, which is unobtrusive to your application if you don't explicitly ask it to do something. Your application code can explicitly ask it to provide the user identity or alter the response to set cookie or remove cookie. To demo external sign in cookie, you need to configure an external provider like Facebook. This flow chart starts from the point Facebook authentication middleware receives the user info from Facebook graph API. For the detailed flow for external provider sign in process, please check out Robert’s tutorial: External Authentication Services
Forms Authentication Middleware(External)
Facebook Authentication Middleware
<After facebook returns authorization code back to your app>
1. GET /signin-facebook?code=<authorization code>&state=<state>
2. Status: 302
Location: /Account/ExternalLoginCallback?loginProvider=Facebook
Middleware code does:
a. Get access token by authorization code from facebook
b. Get user graph data from facebook
c. Convert user graph data into claims identity
d. Sign in claims identity as external type
3. Status: 302
Set-Cookie: .AspNet.External=<ticket token>
External forms middleware does:
a. Convert claims identity to ApplicationTicket
b. Serialize ApplicationTicket to byte array
c. Encrypt and encode byte array to ticket token
d. Set cookie to response
4. Get /Account/ExternalLoginCallback?loginProvider=Facebook
Cookie: .AspNet.External=<ticket token>
5. IdentityAuthenticationManager.GetExternalIdentity()
The extension method will call into OWIN middleware to explicitly authenticate with external type
6. Authenticate cookie and return user claims identity
a. Decode and decrypt ticket token into byte array
b. Deserialize byte array to ApplicationTicket
c. Get claims identity from ApplicationTicket
d. Return identity back to caller
7. Status: 200
Body: external login page
After getting the external identity, check if the user is already registered.
- If no, return external login confirmation page.
- If yes, directly log user in (Not included in this flow)
8. POST /Account/ExternalLoginConfirmation
Body: UserName=test&LoginProvider=Facebook
9. IdentityAuthenticationManager.GetExternalIdentity()
10. Authenticate cookie and return user claims identity
11. Status: 302
Location: /
Web app code does:
a. Create local user via membership provider
b. Associate local user with external identity’s ID claim (facebook id)
c. Sign the external identity in as Application type
d. Redirect to returnUrl or home page
12. Status: 302
Turn claims identity to ticket token and set cookie in response
IdentityAuthenticationManager wraps everything that you need to work with Application and External sign in cookies.
Method
CheckPasswordAndSignIn
Verify user name and password against storage like SQL server and sign in with Application cookie
CreateAndSignInExternalUser
Create user based on external identity from External cookie in storage like SQL server, and sign in user as Application cookie
GetExternalIdentity
Get external identity from External cookie
GetUserIdentityClaims
Replace user id and name claims and add roles and user custom claims from storage.
LinkExternalIdentity
Link external identity with local user in storage
SignIn
Sign out External cookie and sign in Application cookie
SignInExternalIdentity
Get user associating with external identity in storage and sign this user in as Application cookie
SignOut
Sign out from Application cookie
VerifyExternalIdentity
Verify if the external identity has the same issuer as loginProvider
Challenge
Explicitly ask authentication middleware to send challenge to the response. For example, Application forms middleware will challenge to redirect to login page with 302 status code.
GetExternalAuthenticationTypes
Get supported external authentication types which you register in the OWIN middleware pipeline, like Facebook, Google, etc.
The following shows the login code for the ASP.NET MVC template:
What about defining custom values to store? Should we store them using claims and you'll handle the serialization? Up to now, we've implemented a custom ticket, can you show or link us to an example with custom fields storing? and using some of the user data? (for instance, I'd like to store the signed user first name and privileges mask, should I use claims for that and you'll take care of the right serialization logic?)
@Yahav, sure, you can use claims to save custom data. Forms auth middleware will serialize and deserialize it back to claims. Claim support both primitive and non-primitive types, please check out: msdn.microsoft.com/.../ms734687.aspx for more information.