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:
Asp.Net Forms Authentication
OWIN Forms Authentication
Web Farm Support
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:
ApplicaitonSignInCookie Default Values
ExternalSignInCookie Default Values
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.
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.
Defines the domain that cookie is under
Defines if the cookie is http only. It's true by default.
Defines the name of the cookie
Defines the path that cookie is under. By default, it's /.
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.
Defines the expiration of the cookie.
Defines the Login path when unauthorized request will be redirected to.
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
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.
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.
Forms Authentication Middleware(Application)
1. Get /Account/Manage
2. Response Status: 401
AccountController is protected by Authroize attribute, so unauthorized request will return a 401 error.
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
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
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>
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
10. Authenticate cookie and return user claims identity
11. Status: 302
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.
Verify user name and password against storage like SQL server and sign in with Application cookie
Create user based on external identity from External cookie in storage like SQL server, and sign in user as Application cookie
Get external identity from External cookie
Replace user id and name claims and add roles and user custom claims from storage.
Link external identity with local user in storage
Sign out External cookie and sign in Application cookie
Get user associating with external identity in storage and sign this user in as Application cookie
Sign out from Application cookie
Verify if the external identity has the same issuer as loginProvider
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.
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:
Can someone from the team look into this bug: connect.microsoft.com/.../new-webform-app-login-crashes-no-owin-environment ?
@graycrow, thanks for reporting this issue. We are already aware of this issue and fixed it in the next release of Visual Studio. The issue is also mentioned in the preview refresh release note with workaround:
When creating MVC, SPA and Web Form project with special characters in the project name (e.g. space, leading digits, etc.), the project might not work correctly. You will see error like: "No OWIN environment is available for the request" from server.
This is because OWIN uses "<Assembly Name>.Startup" name to find the app start up class. However, since namespace doesn’t support special characters like space, Visual Studio will convert them to underscore in namespace. For example, project name "Project A" will be converted to "Project_A" in namespace. So OWIN is unable to find the correct startup class.
To workaround, Add <add key="owin:AppStartup" value="<Namespace>.Startup, <Assembly name>"/> under <configuration> <appsettings> section. For example: <add key="owin:AppStartup" value="Project_A.Startup, Project A"/>
I can successfully add users to the "Users" and "UserLogins" tables.
How do you put users into Roles. I have tried
Roles.AddUserToRole("username","rolename"); It fails all the time.
AuthenticationManager is gone? How do we authenticate users via username/pass now with the latest RC1 Katana/ASP.NET Identity packages?
Does anyone know if OWIN Forms Authentication allows to disable the redirect to login page?