├── .gitignore ├── .tfignore ├── IdentitySample.sln ├── IdentitySample ├── App_Start │ ├── BundleConfig.cs │ ├── FilterConfig.cs │ ├── IdentityConfig.cs │ ├── RouteConfig.cs │ └── Startup.Auth.cs ├── Content │ ├── Site.css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ └── bootstrap.min.css ├── Controllers │ ├── AccountController.cs │ ├── HomeController.cs │ ├── ManageController.cs │ ├── RolesAdminController.cs │ └── UserAdminController.cs ├── Global.asax ├── Global.asax.cs ├── IdentitySample.csproj ├── Models │ ├── AccountViewModels.cs │ ├── AdminViewModel.cs │ ├── IdentityModels.cs │ └── ManageViewModels.cs ├── Properties │ └── AssemblyInfo.cs ├── Scripts │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery-1.10.2.intellisense.js │ ├── jquery-1.10.2.js │ ├── jquery-1.10.2.min.js │ ├── jquery-1.10.2.min.map │ ├── jquery.validate-vsdoc.js │ ├── jquery.validate.js │ ├── jquery.validate.min.js │ ├── jquery.validate.unobtrusive.js │ ├── jquery.validate.unobtrusive.min.js │ ├── modernizr-2.6.2.js │ ├── respond.js │ └── respond.min.js ├── Startup.cs ├── Views │ ├── Account │ │ ├── ConfirmEmail.cshtml │ │ ├── DisplayEmail.cshtml │ │ ├── ExternalLoginConfirmation.cshtml │ │ ├── ExternalLoginFailure.cshtml │ │ ├── ForgotPassword.cshtml │ │ ├── ForgotPasswordConfirmation.cshtml │ │ ├── Login.cshtml │ │ ├── Register.cshtml │ │ ├── ResetPassword.cshtml │ │ ├── ResetPasswordConfirmation.cshtml │ │ ├── SendCode.cshtml │ │ ├── VerifyCode.cshtml │ │ └── _ExternalLoginsListPartial.cshtml │ ├── Home │ │ ├── About.cshtml │ │ ├── Contact.cshtml │ │ └── Index.cshtml │ ├── Manage │ │ ├── AddPhoneNumber.cshtml │ │ ├── ChangePassword.cshtml │ │ ├── Index.cshtml │ │ ├── ManageLogins.cshtml │ │ ├── SetPassword.cshtml │ │ └── VerifyPhoneNumber.cshtml │ ├── RolesAdmin │ │ ├── Create.cshtml │ │ ├── Delete.cshtml │ │ ├── Details.cshtml │ │ ├── Edit.cshtml │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── Lockout.cshtml │ │ ├── _Layout.cshtml │ │ └── _LoginPartial.cshtml │ ├── UsersAdmin │ │ ├── Create.cshtml │ │ ├── Delete.cshtml │ │ ├── Details.cshtml │ │ ├── Edit.cshtml │ │ └── Index.cshtml │ ├── Web.config │ └── _ViewStart.cshtml ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff └── packages.config └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | *.obj 3 | *.exe 4 | !nuget.exe 5 | *.pdb 6 | *.user 7 | *.aps 8 | *.pch 9 | *.vspscc 10 | *_i.c 11 | *_p.c 12 | *.ncb 13 | *.suo 14 | *.sln.docstates 15 | *.tlb 16 | *.tlh 17 | *.bak 18 | *.cache 19 | *.ilk 20 | *.log 21 | [Bb]in 22 | [Dd]ebug*/ 23 | *.lib 24 | *.sbr 25 | obj/ 26 | [Rr]elease*/ 27 | _ReSharper*/ 28 | [Tt]est[Rr]esult* 29 | *.vssscc 30 | $tf*/ 31 | packages*/ -------------------------------------------------------------------------------- /.tfignore: -------------------------------------------------------------------------------- 1 | \.git -------------------------------------------------------------------------------- /IdentitySample.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30110.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IdentitySample", "IdentitySample\IdentitySample.csproj", "{42F22E71-1AFA-405D-9258-0583A9F01AB9}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {42F22E71-1AFA-405D-9258-0583A9F01AB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {42F22E71-1AFA-405D-9258-0583A9F01AB9}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {42F22E71-1AFA-405D-9258-0583A9F01AB9}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {42F22E71-1AFA-405D-9258-0583A9F01AB9}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /IdentitySample/App_Start/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Optimization; 2 | 3 | namespace IdentitySample 4 | { 5 | public class BundleConfig 6 | { 7 | // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 8 | public static void RegisterBundles(BundleCollection bundles) 9 | { 10 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include( 11 | "~/Scripts/jquery-{version}.js")); 12 | 13 | bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( 14 | "~/Scripts/jquery.validate*")); 15 | 16 | // Use the development version of Modernizr to develop with and learn from. Then, when you're 17 | // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. 18 | bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( 19 | "~/Scripts/modernizr-*")); 20 | 21 | bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( 22 | "~/Scripts/bootstrap.js", 23 | "~/Scripts/respond.js")); 24 | 25 | bundles.Add(new StyleBundle("~/Content/css").Include( 26 | "~/Content/bootstrap.css", 27 | "~/Content/site.css")); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /IdentitySample/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace IdentitySample 4 | { 5 | public class FilterConfig 6 | { 7 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 8 | { 9 | filters.Add(new HandleErrorAttribute()); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /IdentitySample/App_Start/IdentityConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Security.Claims; 3 | using Microsoft.AspNet.Identity; 4 | using Microsoft.AspNet.Identity.EntityFramework; 5 | using Microsoft.AspNet.Identity.Owin; 6 | using Microsoft.Owin; 7 | using Microsoft.Owin.Security; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Data.Entity; 11 | using System.Threading.Tasks; 12 | using System.Web; 13 | 14 | namespace IdentitySample.Models 15 | { 16 | // Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application. 17 | 18 | // *** PASS IN TYPE ARGUMENT TO BASE CLASS: 19 | public class ApplicationUserManager : UserManager 20 | { 21 | // *** ADD INT TYPE ARGUMENT TO CONSTRUCTOR CALL: 22 | public ApplicationUserManager(IUserStore store) 23 | : base(store) 24 | { 25 | } 26 | 27 | public static ApplicationUserManager Create( 28 | IdentityFactoryOptions options, 29 | IOwinContext context) 30 | { 31 | // *** PASS CUSTOM APPLICATION USER STORE AS CONSTRUCTOR ARGUMENT: 32 | var manager = new ApplicationUserManager( 33 | new ApplicationUserStore(context.Get())); 34 | 35 | // Configure validation logic for usernames 36 | 37 | // *** ADD INT TYPE ARGUMENT TO METHOD CALL: 38 | manager.UserValidator = new UserValidator(manager) 39 | { 40 | AllowOnlyAlphanumericUserNames = false, 41 | RequireUniqueEmail = true 42 | }; 43 | 44 | // Configure validation logic for passwords 45 | manager.PasswordValidator = new PasswordValidator 46 | { 47 | RequiredLength = 6, 48 | RequireNonLetterOrDigit = true, 49 | RequireDigit = true, 50 | RequireLowercase = true, 51 | RequireUppercase = true, 52 | }; 53 | 54 | // Configure user lockout defaults 55 | manager.UserLockoutEnabledByDefault = true; 56 | manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5); 57 | manager.MaxFailedAccessAttemptsBeforeLockout = 5; 58 | 59 | // Register two factor authentication providers. 60 | // This application uses Phone and Emails as a step of receiving a 61 | // code for verifying the user You can write your own provider and plug in here. 62 | 63 | // *** ADD INT TYPE ARGUMENT TO METHOD CALL: 64 | manager.RegisterTwoFactorProvider("PhoneCode", 65 | new PhoneNumberTokenProvider 66 | { 67 | MessageFormat = "Your security code is: {0}" 68 | }); 69 | 70 | // *** ADD INT TYPE ARGUMENT TO METHOD CALL: 71 | manager.RegisterTwoFactorProvider("EmailCode", 72 | new EmailTokenProvider 73 | { 74 | Subject = "SecurityCode", 75 | BodyFormat = "Your security code is {0}" 76 | }); 77 | 78 | manager.EmailService = new EmailService(); 79 | manager.SmsService = new SmsService(); 80 | var dataProtectionProvider = options.DataProtectionProvider; 81 | if (dataProtectionProvider != null) 82 | { 83 | // *** ADD INT TYPE ARGUMENT TO METHOD CALL: 84 | manager.UserTokenProvider = 85 | new DataProtectorTokenProvider( 86 | dataProtectionProvider.Create("ASP.NET Identity")); 87 | } 88 | return manager; 89 | } 90 | } 91 | 92 | 93 | // PASS CUSTOM APPLICATION ROLE AND INT AS TYPE ARGUMENTS TO BASE: 94 | public class ApplicationRoleManager : RoleManager 95 | { 96 | // PASS CUSTOM APPLICATION ROLE AND INT AS TYPE ARGUMENTS TO CONSTRUCTOR: 97 | public ApplicationRoleManager(IRoleStore roleStore) 98 | : base(roleStore) 99 | { 100 | } 101 | 102 | // PASS CUSTOM APPLICATION ROLE AS TYPE ARGUMENT: 103 | public static ApplicationRoleManager Create( 104 | IdentityFactoryOptions options, IOwinContext context) 105 | { 106 | return new ApplicationRoleManager( 107 | new ApplicationRoleStore(context.Get())); 108 | } 109 | } 110 | 111 | 112 | public class EmailService : IIdentityMessageService 113 | { 114 | public Task SendAsync(IdentityMessage message) 115 | { 116 | // Plug in your email service here to send an email. 117 | return Task.FromResult(0); 118 | } 119 | } 120 | 121 | 122 | public class SmsService : IIdentityMessageService 123 | { 124 | public Task SendAsync(IdentityMessage message) 125 | { 126 | // Plug in your sms service here to send a text message. 127 | return Task.FromResult(0); 128 | } 129 | } 130 | 131 | // This is useful if you do not want to tear down the database each time you run the application. 132 | // public class ApplicationDbInitializer : DropCreateDatabaseAlways 133 | // This example shows you how to create a new database if the Model changes 134 | public class ApplicationDbInitializer : DropCreateDatabaseIfModelChanges 135 | { 136 | protected override void Seed(ApplicationDbContext context) { 137 | InitializeIdentityForEF(context); 138 | base.Seed(context); 139 | } 140 | 141 | //Create User=Admin@Admin.com with password=Admin@123456 in the Admin role 142 | public static void InitializeIdentityForEF(ApplicationDbContext db) { 143 | var userManager = HttpContext.Current.GetOwinContext().GetUserManager(); 144 | var roleManager = HttpContext.Current.GetOwinContext().Get(); 145 | const string name = "admin@example.com"; 146 | const string password = "Admin@123456"; 147 | const string roleName = "Admin"; 148 | 149 | //Create Role Admin if it does not exist 150 | var role = roleManager.FindByName(roleName); 151 | if (role == null) { 152 | role = new ApplicationRole(roleName); 153 | var roleresult = roleManager.Create(role); 154 | } 155 | 156 | var user = userManager.FindByName(name); 157 | if (user == null) { 158 | user = new ApplicationUser { UserName = name, Email = name }; 159 | var result = userManager.Create(user, password); 160 | result = userManager.SetLockoutEnabled(user.Id, false); 161 | } 162 | 163 | // Add user admin to Role Admin if not already added 164 | var rolesForUser = userManager.GetRoles(user.Id); 165 | if (!rolesForUser.Contains(role.Name)) { 166 | var result = userManager.AddToRole(user.Id, role.Name); 167 | } 168 | } 169 | } 170 | 171 | 172 | public class ApplicationSignInManager : SignInManager 173 | { 174 | public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager) : 175 | base(userManager, authenticationManager) { } 176 | 177 | public override Task CreateUserIdentityAsync(ApplicationUser user) 178 | { 179 | return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager); 180 | } 181 | 182 | public static ApplicationSignInManager Create(IdentityFactoryOptions options, IOwinContext context) 183 | { 184 | return new ApplicationSignInManager(context.GetUserManager(), context.Authentication); 185 | } 186 | } 187 | } -------------------------------------------------------------------------------- /IdentitySample/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | using System.Web.Routing; 3 | 4 | namespace IdentitySample 5 | { 6 | public class RouteConfig 7 | { 8 | public static void RegisterRoutes(RouteCollection routes) 9 | { 10 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 11 | 12 | routes.MapRoute( 13 | name: "Default", 14 | url: "{controller}/{action}/{id}", 15 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 16 | ); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /IdentitySample/App_Start/Startup.Auth.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity; 2 | using Microsoft.AspNet.Identity.Owin; 3 | using Microsoft.Owin; 4 | using Microsoft.Owin.Security.Cookies; 5 | using IdentitySample.Models; 6 | using Owin; 7 | using System; 8 | 9 | namespace IdentitySample 10 | { 11 | public partial class Startup 12 | { 13 | // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 14 | public void ConfigureAuth(IAppBuilder app) 15 | { 16 | // Configure the db context, user manager and role manager to use a single instance per request 17 | app.CreatePerOwinContext(ApplicationDbContext.Create); 18 | app.CreatePerOwinContext(ApplicationUserManager.Create); 19 | app.CreatePerOwinContext(ApplicationRoleManager.Create); 20 | app.CreatePerOwinContext(ApplicationSignInManager.Create); 21 | 22 | // Enable the application to use a cookie to store information for the signed in user 23 | // and to use a cookie to temporarily store information about a user logging in with a third party login provider 24 | // Configure the sign in cookie 25 | app.UseCookieAuthentication(new CookieAuthenticationOptions 26 | { 27 | AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 28 | LoginPath = new PathString("/Account/Login"), 29 | Provider = new CookieAuthenticationProvider 30 | { 31 | // Enables the application to validate the security stamp when the user logs in. 32 | // This is a security feature which is used when you change a password or add an external login to your account. 33 | OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( 34 | validateInterval: TimeSpan.FromMinutes(30), 35 | regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager), 36 | // Need to add THIS line because we added the third type argument (int) above: 37 | getUserIdCallback: (claim) => int.Parse(claim.GetUserId())) 38 | } 39 | }); 40 | app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); 41 | 42 | // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process. 43 | app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5)); 44 | 45 | // Enables the application to remember the second login verification factor such as phone or email. 46 | // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from. 47 | // This is similar to the RememberMe option when you log in. 48 | app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie); 49 | 50 | // Uncomment the following lines to enable logging in with third party login providers 51 | //app.UseMicrosoftAccountAuthentication( 52 | // clientId: "", 53 | // clientSecret: ""); 54 | 55 | //app.UseTwitterAuthentication( 56 | // consumerKey: "", 57 | // consumerSecret: ""); 58 | 59 | //app.UseFacebookAuthentication( 60 | // appId: "", 61 | // appSecret: ""); 62 | 63 | //app.UseGoogleAuthentication( 64 | // clientId: "", 65 | // clientSecret: ""); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /IdentitySample/Content/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Set padding to keep content from hitting the edges */ 7 | .body-content { 8 | padding-left: 15px; 9 | padding-right: 15px; 10 | } 11 | 12 | /* Set width on the form input elements since they're 100% wide by default */ 13 | input, 14 | select, 15 | textarea { 16 | max-width: 280px; 17 | } 18 | 19 | /* styles for validation helpers */ 20 | .field-validation-error { 21 | color: #b94a48; 22 | } 23 | 24 | .field-validation-valid { 25 | display: none; 26 | } 27 | 28 | input.input-validation-error { 29 | border: 1px solid #b94a48; 30 | } 31 | 32 | input[type="checkbox"].input-validation-error { 33 | border: 0 none; 34 | } 35 | 36 | .validation-summary-errors { 37 | color: #b94a48; 38 | } 39 | 40 | .validation-summary-valid { 41 | display: none; 42 | } -------------------------------------------------------------------------------- /IdentitySample/Content/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.0.3 (http://getbootstrap.com) 3 | * Copyright 2013 Twitter, Inc. 4 | * Licensed under http://www.apache.org/licenses/LICENSE-2.0 5 | */ 6 | 7 | .btn-default, 8 | .btn-primary, 9 | .btn-success, 10 | .btn-info, 11 | .btn-warning, 12 | .btn-danger { 13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); 14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); 15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); 16 | } 17 | 18 | .btn-default:active, 19 | .btn-primary:active, 20 | .btn-success:active, 21 | .btn-info:active, 22 | .btn-warning:active, 23 | .btn-danger:active, 24 | .btn-default.active, 25 | .btn-primary.active, 26 | .btn-success.active, 27 | .btn-info.active, 28 | .btn-warning.active, 29 | .btn-danger.active { 30 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); 31 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); 32 | } 33 | 34 | .btn:active, 35 | .btn.active { 36 | background-image: none; 37 | } 38 | 39 | .btn-default { 40 | text-shadow: 0 1px 0 #fff; 41 | background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); 42 | background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%); 43 | background-repeat: repeat-x; 44 | border-color: #dbdbdb; 45 | border-color: #ccc; 46 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 47 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 48 | } 49 | 50 | .btn-default:hover, 51 | .btn-default:focus { 52 | background-color: #e0e0e0; 53 | background-position: 0 -15px; 54 | } 55 | 56 | .btn-default:active, 57 | .btn-default.active { 58 | background-color: #e0e0e0; 59 | border-color: #dbdbdb; 60 | } 61 | 62 | .btn-primary { 63 | background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); 64 | background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); 65 | background-repeat: repeat-x; 66 | border-color: #2b669a; 67 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); 68 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 69 | } 70 | 71 | .btn-primary:hover, 72 | .btn-primary:focus { 73 | background-color: #2d6ca2; 74 | background-position: 0 -15px; 75 | } 76 | 77 | .btn-primary:active, 78 | .btn-primary.active { 79 | background-color: #2d6ca2; 80 | border-color: #2b669a; 81 | } 82 | 83 | .btn-success { 84 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 85 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 86 | background-repeat: repeat-x; 87 | border-color: #3e8f3e; 88 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 89 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 90 | } 91 | 92 | .btn-success:hover, 93 | .btn-success:focus { 94 | background-color: #419641; 95 | background-position: 0 -15px; 96 | } 97 | 98 | .btn-success:active, 99 | .btn-success.active { 100 | background-color: #419641; 101 | border-color: #3e8f3e; 102 | } 103 | 104 | .btn-warning { 105 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 106 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 107 | background-repeat: repeat-x; 108 | border-color: #e38d13; 109 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 110 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 111 | } 112 | 113 | .btn-warning:hover, 114 | .btn-warning:focus { 115 | background-color: #eb9316; 116 | background-position: 0 -15px; 117 | } 118 | 119 | .btn-warning:active, 120 | .btn-warning.active { 121 | background-color: #eb9316; 122 | border-color: #e38d13; 123 | } 124 | 125 | .btn-danger { 126 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 127 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 128 | background-repeat: repeat-x; 129 | border-color: #b92c28; 130 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 131 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 132 | } 133 | 134 | .btn-danger:hover, 135 | .btn-danger:focus { 136 | background-color: #c12e2a; 137 | background-position: 0 -15px; 138 | } 139 | 140 | .btn-danger:active, 141 | .btn-danger.active { 142 | background-color: #c12e2a; 143 | border-color: #b92c28; 144 | } 145 | 146 | .btn-info { 147 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 148 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 149 | background-repeat: repeat-x; 150 | border-color: #28a4c9; 151 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 152 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 153 | } 154 | 155 | .btn-info:hover, 156 | .btn-info:focus { 157 | background-color: #2aabd2; 158 | background-position: 0 -15px; 159 | } 160 | 161 | .btn-info:active, 162 | .btn-info.active { 163 | background-color: #2aabd2; 164 | border-color: #28a4c9; 165 | } 166 | 167 | .thumbnail, 168 | .img-thumbnail { 169 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 170 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 171 | } 172 | 173 | .dropdown-menu > li > a:hover, 174 | .dropdown-menu > li > a:focus { 175 | background-color: #e8e8e8; 176 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 177 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 178 | background-repeat: repeat-x; 179 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 180 | } 181 | 182 | .dropdown-menu > .active > a, 183 | .dropdown-menu > .active > a:hover, 184 | .dropdown-menu > .active > a:focus { 185 | background-color: #357ebd; 186 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 187 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 188 | background-repeat: repeat-x; 189 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 190 | } 191 | 192 | .navbar-default { 193 | background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); 194 | background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%); 195 | background-repeat: repeat-x; 196 | border-radius: 4px; 197 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 198 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 199 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); 200 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); 201 | } 202 | 203 | .navbar-default .navbar-nav > .active > a { 204 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); 205 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); 206 | background-repeat: repeat-x; 207 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); 208 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); 209 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); 210 | } 211 | 212 | .navbar-brand, 213 | .navbar-nav > li > a { 214 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); 215 | } 216 | 217 | .navbar-inverse { 218 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%); 219 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%); 220 | background-repeat: repeat-x; 221 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 222 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 223 | } 224 | 225 | .navbar-inverse .navbar-nav > .active > a { 226 | background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%); 227 | background-image: linear-gradient(to bottom, #222222 0%, #282828 100%); 228 | background-repeat: repeat-x; 229 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); 230 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); 231 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); 232 | } 233 | 234 | .navbar-inverse .navbar-brand, 235 | .navbar-inverse .navbar-nav > li > a { 236 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 237 | } 238 | 239 | .navbar-static-top, 240 | .navbar-fixed-top, 241 | .navbar-fixed-bottom { 242 | border-radius: 0; 243 | } 244 | 245 | .alert { 246 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2); 247 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); 248 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); 249 | } 250 | 251 | .alert-success { 252 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 253 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 254 | background-repeat: repeat-x; 255 | border-color: #b2dba1; 256 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 257 | } 258 | 259 | .alert-info { 260 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 261 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 262 | background-repeat: repeat-x; 263 | border-color: #9acfea; 264 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 265 | } 266 | 267 | .alert-warning { 268 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 269 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 270 | background-repeat: repeat-x; 271 | border-color: #f5e79e; 272 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 273 | } 274 | 275 | .alert-danger { 276 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 277 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 278 | background-repeat: repeat-x; 279 | border-color: #dca7a7; 280 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 281 | } 282 | 283 | .progress { 284 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 285 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 286 | background-repeat: repeat-x; 287 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 288 | } 289 | 290 | .progress-bar { 291 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); 292 | background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); 293 | background-repeat: repeat-x; 294 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); 295 | } 296 | 297 | .progress-bar-success { 298 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 299 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 300 | background-repeat: repeat-x; 301 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 302 | } 303 | 304 | .progress-bar-info { 305 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 306 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 307 | background-repeat: repeat-x; 308 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 309 | } 310 | 311 | .progress-bar-warning { 312 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 313 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 314 | background-repeat: repeat-x; 315 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 316 | } 317 | 318 | .progress-bar-danger { 319 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 320 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 321 | background-repeat: repeat-x; 322 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 323 | } 324 | 325 | .list-group { 326 | border-radius: 4px; 327 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 328 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 329 | } 330 | 331 | .list-group-item.active, 332 | .list-group-item.active:hover, 333 | .list-group-item.active:focus { 334 | text-shadow: 0 -1px 0 #3071a9; 335 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); 336 | background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); 337 | background-repeat: repeat-x; 338 | border-color: #3278b3; 339 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); 340 | } 341 | 342 | .panel { 343 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 344 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 345 | } 346 | 347 | .panel-default > .panel-heading { 348 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 349 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 350 | background-repeat: repeat-x; 351 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 352 | } 353 | 354 | .panel-primary > .panel-heading { 355 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 356 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 357 | background-repeat: repeat-x; 358 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 359 | } 360 | 361 | .panel-success > .panel-heading { 362 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 363 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 364 | background-repeat: repeat-x; 365 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 366 | } 367 | 368 | .panel-info > .panel-heading { 369 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 370 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 371 | background-repeat: repeat-x; 372 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 373 | } 374 | 375 | .panel-warning > .panel-heading { 376 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 377 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 378 | background-repeat: repeat-x; 379 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 380 | } 381 | 382 | .panel-danger > .panel-heading { 383 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 384 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 385 | background-repeat: repeat-x; 386 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 387 | } 388 | 389 | .well { 390 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 391 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 392 | background-repeat: repeat-x; 393 | border-color: #dcdcdc; 394 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 395 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); 396 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); 397 | } -------------------------------------------------------------------------------- /IdentitySample/Content/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.0.3 (http://getbootstrap.com) 3 | * Copyright 2013 Twitter, Inc. 4 | * Licensed under http://www.apache.org/licenses/LICENSE-2.0 5 | */ 6 | 7 | .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);background-repeat:repeat-x;border-color:#2b669a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff2d6ca2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff419641',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffeb9316',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);background-repeat:repeat-x;border-color:#b92c28;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc12e2a',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2aabd2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff3f3f3',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff282828',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} -------------------------------------------------------------------------------- /IdentitySample/Controllers/AccountController.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using IdentitySample.Models; 3 | using Microsoft.AspNet.Identity; 4 | using Microsoft.AspNet.Identity.Owin; 5 | using Microsoft.Owin.Security; 6 | using System; 7 | using System.Linq; 8 | using System.Security.Claims; 9 | using System.Threading.Tasks; 10 | using System.Web; 11 | using System.Web.Mvc; 12 | 13 | namespace IdentitySample.Controllers 14 | { 15 | [Authorize] 16 | public class AccountController : Controller 17 | { 18 | public AccountController() 19 | { 20 | } 21 | 22 | public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager ) 23 | { 24 | UserManager = userManager; 25 | SignInManager = signInManager; 26 | } 27 | 28 | private ApplicationUserManager _userManager; 29 | public ApplicationUserManager UserManager 30 | { 31 | get 32 | { 33 | return _userManager ?? HttpContext.GetOwinContext().GetUserManager(); 34 | } 35 | private set 36 | { 37 | _userManager = value; 38 | } 39 | } 40 | 41 | // 42 | // GET: /Account/Login 43 | [AllowAnonymous] 44 | public ActionResult Login(string returnUrl) 45 | { 46 | ViewBag.ReturnUrl = returnUrl; 47 | return View(); 48 | } 49 | 50 | private ApplicationSignInManager _signInManager; 51 | 52 | public ApplicationSignInManager SignInManager 53 | { 54 | get 55 | { 56 | return _signInManager ?? HttpContext.GetOwinContext().Get(); 57 | } 58 | private set { _signInManager = value; } 59 | } 60 | 61 | // 62 | // POST: /Account/Login 63 | [HttpPost] 64 | [AllowAnonymous] 65 | [ValidateAntiForgeryToken] 66 | public async Task Login(LoginViewModel model, string returnUrl) 67 | { 68 | if (!ModelState.IsValid) 69 | { 70 | return View(model); 71 | } 72 | 73 | // This doen't count login failures towards lockout only two factor authentication 74 | // To enable password failures to trigger lockout, change to shouldLockout: true 75 | var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false); 76 | switch (result) 77 | { 78 | case SignInStatus.Success: 79 | return RedirectToLocal(returnUrl); 80 | case SignInStatus.LockedOut: 81 | return View("Lockout"); 82 | case SignInStatus.RequiresVerification: 83 | return RedirectToAction("SendCode", new { ReturnUrl = returnUrl }); 84 | case SignInStatus.Failure: 85 | default: 86 | ModelState.AddModelError("", "Invalid login attempt."); 87 | return View(model); 88 | } 89 | } 90 | 91 | // 92 | // GET: /Account/VerifyCode 93 | [AllowAnonymous] 94 | public async Task VerifyCode(string provider, string returnUrl) 95 | { 96 | // Require that the user has already logged in via username/password or external login 97 | if (!await SignInManager.HasBeenVerifiedAsync()) 98 | { 99 | return View("Error"); 100 | } 101 | var user = await UserManager.FindByIdAsync(await SignInManager.GetVerifiedUserIdAsync()); 102 | if (user != null) 103 | { 104 | ViewBag.Status = "For DEMO purposes the current " + provider + " code is: " + await UserManager.GenerateTwoFactorTokenAsync(user.Id, provider); 105 | } 106 | return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl }); 107 | } 108 | 109 | // 110 | // POST: /Account/VerifyCode 111 | [HttpPost] 112 | [AllowAnonymous] 113 | [ValidateAntiForgeryToken] 114 | public async Task VerifyCode(VerifyCodeViewModel model) 115 | { 116 | if (!ModelState.IsValid) 117 | { 118 | return View(model); 119 | } 120 | 121 | var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: false, rememberBrowser: model.RememberBrowser); 122 | switch (result) 123 | { 124 | case SignInStatus.Success: 125 | return RedirectToLocal(model.ReturnUrl); 126 | case SignInStatus.LockedOut: 127 | return View("Lockout"); 128 | case SignInStatus.Failure: 129 | default: 130 | ModelState.AddModelError("", "Invalid code."); 131 | return View(model); 132 | } 133 | } 134 | 135 | // 136 | // GET: /Account/Register 137 | [AllowAnonymous] 138 | public ActionResult Register() 139 | { 140 | return View(); 141 | } 142 | 143 | // 144 | // POST: /Account/Register 145 | [HttpPost] 146 | [AllowAnonymous] 147 | [ValidateAntiForgeryToken] 148 | public async Task Register(RegisterViewModel model) 149 | { 150 | if (ModelState.IsValid) 151 | { 152 | var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; 153 | var result = await UserManager.CreateAsync(user, model.Password); 154 | if (result.Succeeded) 155 | { 156 | var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id); 157 | var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme); 158 | await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking this link: link"); 159 | ViewBag.Link = callbackUrl; 160 | return View("DisplayEmail"); 161 | } 162 | AddErrors(result); 163 | } 164 | 165 | // If we got this far, something failed, redisplay form 166 | return View(model); 167 | } 168 | 169 | // 170 | // GET: /Account/ConfirmEmail 171 | [AllowAnonymous] 172 | public async Task ConfirmEmail(int userId, string code) 173 | { 174 | if (userId > 0 || code == null) 175 | { 176 | var result = await UserManager.ConfirmEmailAsync(userId, code); 177 | return View(result.Succeeded ? "ConfirmEmail" : "Error"); 178 | } 179 | return View("Error"); 180 | } 181 | 182 | // 183 | // GET: /Account/ForgotPassword 184 | [AllowAnonymous] 185 | public ActionResult ForgotPassword() 186 | { 187 | return View(); 188 | } 189 | 190 | // 191 | // POST: /Account/ForgotPassword 192 | [HttpPost] 193 | [AllowAnonymous] 194 | [ValidateAntiForgeryToken] 195 | public async Task ForgotPassword(ForgotPasswordViewModel model) 196 | { 197 | if (ModelState.IsValid) 198 | { 199 | var user = await UserManager.FindByNameAsync(model.Email); 200 | if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id))) 201 | { 202 | // Don't reveal that the user does not exist or is not confirmed 203 | return View("ForgotPasswordConfirmation"); 204 | } 205 | 206 | var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id); 207 | var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme); 208 | await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here: link"); 209 | ViewBag.Link = callbackUrl; 210 | return View("ForgotPasswordConfirmation"); 211 | } 212 | 213 | // If we got this far, something failed, redisplay form 214 | return View(model); 215 | } 216 | 217 | // 218 | // GET: /Account/ForgotPasswordConfirmation 219 | [AllowAnonymous] 220 | public ActionResult ForgotPasswordConfirmation() 221 | { 222 | return View(); 223 | } 224 | 225 | // 226 | // GET: /Account/ResetPassword 227 | [AllowAnonymous] 228 | public ActionResult ResetPassword(string code) 229 | { 230 | return code == null ? View("Error") : View(); 231 | } 232 | 233 | // 234 | // POST: /Account/ResetPassword 235 | [HttpPost] 236 | [AllowAnonymous] 237 | [ValidateAntiForgeryToken] 238 | public async Task ResetPassword(ResetPasswordViewModel model) 239 | { 240 | if (!ModelState.IsValid) 241 | { 242 | return View(model); 243 | } 244 | var user = await UserManager.FindByNameAsync(model.Email); 245 | if (user == null) 246 | { 247 | // Don't reveal that the user does not exist 248 | return RedirectToAction("ResetPasswordConfirmation", "Account"); 249 | } 250 | var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password); 251 | if (result.Succeeded) 252 | { 253 | return RedirectToAction("ResetPasswordConfirmation", "Account"); 254 | } 255 | AddErrors(result); 256 | return View(); 257 | } 258 | 259 | // 260 | // GET: /Account/ResetPasswordConfirmation 261 | [AllowAnonymous] 262 | public ActionResult ResetPasswordConfirmation() 263 | { 264 | return View(); 265 | } 266 | 267 | // 268 | // POST: /Account/ExternalLogin 269 | [HttpPost] 270 | [AllowAnonymous] 271 | [ValidateAntiForgeryToken] 272 | public ActionResult ExternalLogin(string provider, string returnUrl) 273 | { 274 | // Request a redirect to the external login provider 275 | return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl })); 276 | } 277 | 278 | // 279 | // GET: /Account/SendCode 280 | [AllowAnonymous] 281 | public async Task SendCode(string returnUrl) 282 | { 283 | var userId = await SignInManager.GetVerifiedUserIdAsync(); 284 | if (userId > 0) 285 | { 286 | var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(userId); 287 | var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList(); 288 | return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl }); 289 | } 290 | return View("Error"); 291 | } 292 | 293 | // 294 | // POST: /Account/SendCode 295 | [HttpPost] 296 | [AllowAnonymous] 297 | [ValidateAntiForgeryToken] 298 | public async Task SendCode(SendCodeViewModel model) 299 | { 300 | if (!ModelState.IsValid) 301 | { 302 | return View(); 303 | } 304 | 305 | // Generate the token and send it 306 | if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider)) 307 | { 308 | return View("Error"); 309 | } 310 | return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl }); 311 | } 312 | 313 | // 314 | // GET: /Account/ExternalLoginCallback 315 | [AllowAnonymous] 316 | public async Task ExternalLoginCallback(string returnUrl) 317 | { 318 | var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); 319 | if (loginInfo == null) 320 | { 321 | return RedirectToAction("Login"); 322 | } 323 | 324 | // Sign in the user with this external login provider if the user already has a login 325 | var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false); 326 | switch (result) 327 | { 328 | case SignInStatus.Success: 329 | return RedirectToLocal(returnUrl); 330 | case SignInStatus.LockedOut: 331 | return View("Lockout"); 332 | case SignInStatus.RequiresVerification: 333 | return RedirectToAction("SendCode", new { ReturnUrl = returnUrl }); 334 | case SignInStatus.Failure: 335 | default: 336 | // If the user does not have an account, then prompt the user to create an account 337 | ViewBag.ReturnUrl = returnUrl; 338 | ViewBag.LoginProvider = loginInfo.Login.LoginProvider; 339 | return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email }); 340 | } 341 | } 342 | 343 | // 344 | // POST: /Account/ExternalLoginConfirmation 345 | [HttpPost] 346 | [AllowAnonymous] 347 | [ValidateAntiForgeryToken] 348 | public async Task ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl) 349 | { 350 | if (User.Identity.IsAuthenticated) 351 | { 352 | return RedirectToAction("Index", "Manage"); 353 | } 354 | 355 | if (ModelState.IsValid) 356 | { 357 | // Get the information about the user from the external login provider 358 | var info = await AuthenticationManager.GetExternalLoginInfoAsync(); 359 | if (info == null) 360 | { 361 | return View("ExternalLoginFailure"); 362 | } 363 | var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; 364 | var result = await UserManager.CreateAsync(user); 365 | if (result.Succeeded) 366 | { 367 | result = await UserManager.AddLoginAsync(user.Id, info.Login); 368 | if (result.Succeeded) 369 | { 370 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false); 371 | return RedirectToLocal(returnUrl); 372 | } 373 | } 374 | AddErrors(result); 375 | } 376 | 377 | ViewBag.ReturnUrl = returnUrl; 378 | return View(model); 379 | } 380 | 381 | // 382 | // POST: /Account/LogOff 383 | [HttpPost] 384 | [ValidateAntiForgeryToken] 385 | public ActionResult LogOff() 386 | { 387 | AuthenticationManager.SignOut(); 388 | return RedirectToAction("Index", "Home"); 389 | } 390 | 391 | // 392 | // GET: /Account/ExternalLoginFailure 393 | [AllowAnonymous] 394 | public ActionResult ExternalLoginFailure() 395 | { 396 | return View(); 397 | } 398 | 399 | #region Helpers 400 | // Used for XSRF protection when adding external logins 401 | private const string XsrfKey = "XsrfId"; 402 | 403 | private IAuthenticationManager AuthenticationManager 404 | { 405 | get 406 | { 407 | return HttpContext.GetOwinContext().Authentication; 408 | } 409 | } 410 | 411 | private void AddErrors(IdentityResult result) 412 | { 413 | foreach (var error in result.Errors) 414 | { 415 | ModelState.AddModelError("", error); 416 | } 417 | } 418 | 419 | private ActionResult RedirectToLocal(string returnUrl) 420 | { 421 | if (Url.IsLocalUrl(returnUrl)) 422 | { 423 | return Redirect(returnUrl); 424 | } 425 | return RedirectToAction("Index", "Home"); 426 | } 427 | 428 | internal class ChallengeResult : HttpUnauthorizedResult 429 | { 430 | public ChallengeResult(string provider, string redirectUri) 431 | : this(provider, redirectUri, null) 432 | { 433 | } 434 | 435 | public ChallengeResult(string provider, string redirectUri, string userId) 436 | { 437 | LoginProvider = provider; 438 | RedirectUri = redirectUri; 439 | UserId = userId; 440 | } 441 | 442 | public string LoginProvider { get; set; } 443 | public string RedirectUri { get; set; } 444 | public string UserId { get; set; } 445 | 446 | public override void ExecuteResult(ControllerContext context) 447 | { 448 | var properties = new AuthenticationProperties { RedirectUri = RedirectUri }; 449 | if (UserId != null) 450 | { 451 | properties.Dictionary[XsrfKey] = UserId; 452 | } 453 | context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider); 454 | } 455 | } 456 | #endregion 457 | } 458 | } -------------------------------------------------------------------------------- /IdentitySample/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace IdentitySample.Controllers 4 | { 5 | public class HomeController : Controller 6 | { 7 | public ActionResult Index() 8 | { 9 | return View(); 10 | } 11 | 12 | [Authorize] 13 | public ActionResult About() 14 | { 15 | ViewBag.Message = "Your app description page."; 16 | 17 | return View(); 18 | } 19 | 20 | public ActionResult Contact() 21 | { 22 | ViewBag.Message = "Your contact page."; 23 | 24 | return View(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /IdentitySample/Controllers/ManageController.cs: -------------------------------------------------------------------------------- 1 | using IdentitySample.Models; 2 | using Microsoft.AspNet.Identity; 3 | using Microsoft.AspNet.Identity.Owin; 4 | using Microsoft.Owin.Security; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Web; 8 | using System.Web.Mvc; 9 | 10 | namespace IdentitySample.Controllers 11 | { 12 | [Authorize] 13 | public class ManageController : Controller 14 | { 15 | public ManageController() 16 | { 17 | } 18 | 19 | public ManageController(ApplicationUserManager userManager) 20 | { 21 | UserManager = userManager; 22 | } 23 | 24 | private ApplicationUserManager _userManager; 25 | public ApplicationUserManager UserManager 26 | { 27 | get 28 | { 29 | return _userManager ?? HttpContext.GetOwinContext().GetUserManager(); 30 | } 31 | private set 32 | { 33 | _userManager = value; 34 | } 35 | } 36 | 37 | // 38 | // GET: /Account/Index 39 | public async Task Index(ManageMessageId? message) 40 | { 41 | ViewBag.StatusMessage = 42 | message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." 43 | : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." 44 | : message == ManageMessageId.SetTwoFactorSuccess ? "Your two factor provider has been set." 45 | : message == ManageMessageId.Error ? "An error has occurred." 46 | : message == ManageMessageId.AddPhoneSuccess ? "The phone number was added." 47 | : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed." 48 | : ""; 49 | 50 | var model = new IndexViewModel 51 | { 52 | HasPassword = HasPassword(), 53 | PhoneNumber = await UserManager.GetPhoneNumberAsync(User.Identity.GetUserId()), 54 | TwoFactor = await UserManager.GetTwoFactorEnabledAsync(User.Identity.GetUserId()), 55 | Logins = await UserManager.GetLoginsAsync(User.Identity.GetUserId()), 56 | BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(User.Identity.GetUserId().ToString()) 57 | }; 58 | return View(model); 59 | } 60 | 61 | // 62 | // GET: /Account/RemoveLogin 63 | public ActionResult RemoveLogin() 64 | { 65 | var linkedAccounts = UserManager.GetLogins(User.Identity.GetUserId()); 66 | ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1; 67 | return View(linkedAccounts); 68 | } 69 | 70 | // 71 | // POST: /Manage/RemoveLogin 72 | [HttpPost] 73 | [ValidateAntiForgeryToken] 74 | public async Task RemoveLogin(string loginProvider, string providerKey) 75 | { 76 | ManageMessageId? message; 77 | var result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey)); 78 | if (result.Succeeded) 79 | { 80 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 81 | if (user != null) 82 | { 83 | await SignInAsync(user, isPersistent: false); 84 | } 85 | message = ManageMessageId.RemoveLoginSuccess; 86 | } 87 | else 88 | { 89 | message = ManageMessageId.Error; 90 | } 91 | return RedirectToAction("ManageLogins", new { Message = message }); 92 | } 93 | 94 | // 95 | // GET: /Account/AddPhoneNumber 96 | public ActionResult AddPhoneNumber() 97 | { 98 | return View(); 99 | } 100 | 101 | // 102 | // POST: /Account/AddPhoneNumber 103 | [HttpPost] 104 | [ValidateAntiForgeryToken] 105 | public async Task AddPhoneNumber(AddPhoneNumberViewModel model) 106 | { 107 | if (!ModelState.IsValid) 108 | { 109 | return View(model); 110 | } 111 | // Generate the token and send it 112 | var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), model.Number); 113 | if (UserManager.SmsService != null) 114 | { 115 | var message = new IdentityMessage 116 | { 117 | Destination = model.Number, 118 | Body = "Your security code is: " + code 119 | }; 120 | await UserManager.SmsService.SendAsync(message); 121 | } 122 | return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number }); 123 | } 124 | 125 | // 126 | // POST: /Manage/RememberBrowser 127 | [HttpPost] 128 | public ActionResult RememberBrowser() 129 | { 130 | var rememberBrowserIdentity = AuthenticationManager.CreateTwoFactorRememberBrowserIdentity(User.Identity.GetUserId().ToString()); 131 | AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = true }, rememberBrowserIdentity); 132 | return RedirectToAction("Index", "Manage"); 133 | } 134 | 135 | // 136 | // POST: /Manage/ForgetBrowser 137 | [HttpPost] 138 | public ActionResult ForgetBrowser() 139 | { 140 | AuthenticationManager.SignOut(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie); 141 | return RedirectToAction("Index", "Manage"); 142 | } 143 | 144 | // 145 | // POST: /Manage/EnableTFA 146 | [HttpPost] 147 | public async Task EnableTFA() 148 | { 149 | await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true); 150 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 151 | if (user != null) 152 | { 153 | await SignInAsync(user, isPersistent: false); 154 | } 155 | return RedirectToAction("Index", "Manage"); 156 | } 157 | 158 | // 159 | // POST: /Manage/DisableTFA 160 | [HttpPost] 161 | public async Task DisableTFA() 162 | { 163 | await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), false); 164 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 165 | if (user != null) 166 | { 167 | await SignInAsync(user, isPersistent: false); 168 | } 169 | return RedirectToAction("Index", "Manage"); 170 | } 171 | 172 | // 173 | // GET: /Account/VerifyPhoneNumber 174 | public async Task VerifyPhoneNumber(string phoneNumber) 175 | { 176 | // This code allows you exercise the flow without actually sending codes 177 | // For production use please register a SMS provider in IdentityConfig and generate a code here. 178 | var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), phoneNumber); 179 | ViewBag.Status = "For DEMO purposes only, the current code is " + code; 180 | return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber }); 181 | } 182 | 183 | // 184 | // POST: /Account/VerifyPhoneNumber 185 | [HttpPost] 186 | [ValidateAntiForgeryToken] 187 | public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model) 188 | { 189 | if (!ModelState.IsValid) 190 | { 191 | return View(model); 192 | } 193 | var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code); 194 | if (result.Succeeded) 195 | { 196 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 197 | if (user != null) 198 | { 199 | await SignInAsync(user, isPersistent: false); 200 | } 201 | return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess }); 202 | } 203 | // If we got this far, something failed, redisplay form 204 | ModelState.AddModelError("", "Failed to verify phone"); 205 | return View(model); 206 | } 207 | 208 | // 209 | // GET: /Account/RemovePhoneNumber 210 | public async Task RemovePhoneNumber() 211 | { 212 | var result = await UserManager.SetPhoneNumberAsync(User.Identity.GetUserId(), null); 213 | if (!result.Succeeded) 214 | { 215 | return RedirectToAction("Index", new { Message = ManageMessageId.Error }); 216 | } 217 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 218 | if (user != null) 219 | { 220 | await SignInAsync(user, isPersistent: false); 221 | } 222 | return RedirectToAction("Index", new { Message = ManageMessageId.RemovePhoneSuccess }); 223 | } 224 | 225 | // 226 | // GET: /Manage/ChangePassword 227 | public ActionResult ChangePassword() 228 | { 229 | return View(); 230 | } 231 | 232 | // 233 | // POST: /Account/Manage 234 | [HttpPost] 235 | [ValidateAntiForgeryToken] 236 | public async Task ChangePassword(ChangePasswordViewModel model) 237 | { 238 | if (!ModelState.IsValid) 239 | { 240 | return View(model); 241 | } 242 | var result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); 243 | if (result.Succeeded) 244 | { 245 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 246 | if (user != null) 247 | { 248 | await SignInAsync(user, isPersistent: false); 249 | } 250 | return RedirectToAction("Index", new { Message = ManageMessageId.ChangePasswordSuccess }); 251 | } 252 | AddErrors(result); 253 | return View(model); 254 | } 255 | 256 | // 257 | // GET: /Manage/SetPassword 258 | public ActionResult SetPassword() 259 | { 260 | return View(); 261 | } 262 | 263 | // 264 | // POST: /Manage/SetPassword 265 | [HttpPost] 266 | [ValidateAntiForgeryToken] 267 | public async Task SetPassword(SetPasswordViewModel model) 268 | { 269 | if (ModelState.IsValid) 270 | { 271 | var result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword); 272 | if (result.Succeeded) 273 | { 274 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 275 | if (user != null) 276 | { 277 | await SignInAsync(user, isPersistent: false); 278 | } 279 | return RedirectToAction("Index", new { Message = ManageMessageId.SetPasswordSuccess }); 280 | } 281 | AddErrors(result); 282 | } 283 | 284 | // If we got this far, something failed, redisplay form 285 | return View(model); 286 | } 287 | 288 | // 289 | // GET: /Account/Manage 290 | public async Task ManageLogins(ManageMessageId? message) 291 | { 292 | ViewBag.StatusMessage = 293 | message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." 294 | : message == ManageMessageId.Error ? "An error has occurred." 295 | : ""; 296 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 297 | if (user == null) 298 | { 299 | return View("Error"); 300 | } 301 | var userLogins = await UserManager.GetLoginsAsync(User.Identity.GetUserId()); 302 | var otherLogins = AuthenticationManager.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList(); 303 | ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1; 304 | return View(new ManageLoginsViewModel 305 | { 306 | CurrentLogins = userLogins, 307 | OtherLogins = otherLogins 308 | }); 309 | } 310 | 311 | // 312 | // POST: /Manage/LinkLogin 313 | [HttpPost] 314 | [ValidateAntiForgeryToken] 315 | public ActionResult LinkLogin(string provider) 316 | { 317 | // Request a redirect to the external login provider to link a login for the current user 318 | return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage"), User.Identity.GetUserId().ToString()); 319 | } 320 | 321 | // 322 | // GET: /Manage/LinkLoginCallback 323 | public async Task LinkLoginCallback() 324 | { 325 | var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId().ToString()); 326 | if (loginInfo == null) 327 | { 328 | return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); 329 | } 330 | var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login); 331 | return result.Succeeded ? RedirectToAction("ManageLogins") : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); 332 | } 333 | 334 | #region Helpers 335 | // Used for XSRF protection when adding external logins 336 | private const string XsrfKey = "XsrfId"; 337 | 338 | private IAuthenticationManager AuthenticationManager 339 | { 340 | get 341 | { 342 | return HttpContext.GetOwinContext().Authentication; 343 | } 344 | } 345 | 346 | private async Task SignInAsync(ApplicationUser user, bool isPersistent) 347 | { 348 | AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie, DefaultAuthenticationTypes.TwoFactorCookie); 349 | AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent }, await user.GenerateUserIdentityAsync(UserManager)); 350 | } 351 | 352 | private void AddErrors(IdentityResult result) 353 | { 354 | foreach (var error in result.Errors) 355 | { 356 | ModelState.AddModelError("", error); 357 | } 358 | } 359 | 360 | private bool HasPassword() 361 | { 362 | var user = UserManager.FindById(User.Identity.GetUserId()); 363 | if (user != null) 364 | { 365 | return user.PasswordHash != null; 366 | } 367 | return false; 368 | } 369 | 370 | private bool HasPhoneNumber() 371 | { 372 | var user = UserManager.FindById(User.Identity.GetUserId()); 373 | if (user != null) 374 | { 375 | return user.PhoneNumber != null; 376 | } 377 | return false; 378 | } 379 | 380 | public enum ManageMessageId 381 | { 382 | AddPhoneSuccess, 383 | ChangePasswordSuccess, 384 | SetTwoFactorSuccess, 385 | SetPasswordSuccess, 386 | RemoveLoginSuccess, 387 | RemovePhoneSuccess, 388 | Error 389 | } 390 | 391 | #endregion 392 | } 393 | } -------------------------------------------------------------------------------- /IdentitySample/Controllers/RolesAdminController.cs: -------------------------------------------------------------------------------- 1 | using IdentitySample.Models; 2 | using Microsoft.AspNet.Identity; 3 | using Microsoft.AspNet.Identity.Owin; 4 | using Microsoft.AspNet.Identity.EntityFramework; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Threading.Tasks; 8 | using System.Web; 9 | using System.Web.Mvc; 10 | using System.Collections.Generic; 11 | 12 | namespace IdentitySample.Controllers 13 | { 14 | [Authorize(Roles = "Admin")] 15 | public class RolesAdminController : Controller 16 | { 17 | public RolesAdminController() 18 | { 19 | } 20 | 21 | public RolesAdminController(ApplicationUserManager userManager, 22 | ApplicationRoleManager roleManager) 23 | { 24 | UserManager = userManager; 25 | RoleManager = roleManager; 26 | } 27 | 28 | private ApplicationUserManager _userManager; 29 | public ApplicationUserManager UserManager 30 | { 31 | get 32 | { 33 | return _userManager ?? HttpContext.GetOwinContext().GetUserManager(); 34 | } 35 | set 36 | { 37 | _userManager = value; 38 | } 39 | } 40 | 41 | private ApplicationRoleManager _roleManager; 42 | public ApplicationRoleManager RoleManager 43 | { 44 | get 45 | { 46 | return _roleManager ?? HttpContext.GetOwinContext().Get(); 47 | } 48 | private set 49 | { 50 | _roleManager = value; 51 | } 52 | } 53 | 54 | // 55 | // GET: /Roles/ 56 | public ActionResult Index() 57 | { 58 | return View(RoleManager.Roles); 59 | } 60 | 61 | // 62 | // GET: /Roles/Details/5 63 | public async Task Details(int id) 64 | { 65 | if (id > 0) 66 | { 67 | var role = await RoleManager.FindByIdAsync(id); 68 | // Get the list of Users in this Role 69 | var users = new List(); 70 | 71 | // Get the list of Users in this Role 72 | foreach (var user in UserManager.Users.ToList()) 73 | { 74 | if (await UserManager.IsInRoleAsync(user.Id, role.Name)) 75 | { 76 | users.Add(user); 77 | } 78 | } 79 | 80 | ViewBag.Users = users; 81 | ViewBag.UserCount = users.Count(); 82 | return View(role); 83 | } 84 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 85 | } 86 | 87 | // 88 | // GET: /Roles/Create 89 | public ActionResult Create() 90 | { 91 | return View(); 92 | } 93 | 94 | // 95 | // POST: /Roles/Create 96 | [HttpPost] 97 | public async Task Create(RoleViewModel roleViewModel) 98 | { 99 | if (ModelState.IsValid) 100 | { 101 | // Use ApplicationRole, not IdentityRole: 102 | var role = new ApplicationRole(roleViewModel.Name); 103 | var roleresult = await RoleManager.CreateAsync(role); 104 | if (!roleresult.Succeeded) 105 | { 106 | ModelState.AddModelError("", roleresult.Errors.First()); 107 | return View(); 108 | } 109 | return RedirectToAction("Index"); 110 | } 111 | return View(); 112 | } 113 | 114 | // 115 | // GET: /Roles/Edit/Admin 116 | public async Task Edit(int id) 117 | { 118 | if (id > 0) 119 | { 120 | var role = await RoleManager.FindByIdAsync(id); 121 | if (role == null) 122 | { 123 | return HttpNotFound(); 124 | } 125 | RoleViewModel roleModel = new RoleViewModel { Id = role.Id, Name = role.Name }; 126 | return View(roleModel); 127 | } 128 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 129 | } 130 | 131 | // 132 | // POST: /Roles/Edit/5 133 | [HttpPost] 134 | 135 | [ValidateAntiForgeryToken] 136 | public async Task Edit([Bind(Include = "Name,Id")] RoleViewModel roleModel) 137 | { 138 | if (ModelState.IsValid) 139 | { 140 | var role = await RoleManager.FindByIdAsync(roleModel.Id); 141 | role.Name = roleModel.Name; 142 | await RoleManager.UpdateAsync(role); 143 | return RedirectToAction("Index"); 144 | } 145 | return View(); 146 | } 147 | 148 | // 149 | // GET: /Roles/Delete/5 150 | public async Task Delete(int id) 151 | { 152 | if (id > 0) 153 | { 154 | var role = await RoleManager.FindByIdAsync(id); 155 | if (role == null) 156 | { 157 | return HttpNotFound(); 158 | } 159 | return View(role); 160 | } 161 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 162 | } 163 | 164 | // 165 | // POST: /Roles/Delete/5 166 | [HttpPost, ActionName("Delete")] 167 | [ValidateAntiForgeryToken] 168 | public async Task DeleteConfirmed(int id, string deleteUser) 169 | { 170 | if (ModelState.IsValid) 171 | { 172 | if (id > 0) 173 | { 174 | var role = await RoleManager.FindByIdAsync(id); 175 | if (role == null) 176 | { 177 | return HttpNotFound(); 178 | } 179 | IdentityResult result; 180 | if (deleteUser != null) 181 | { 182 | result = await RoleManager.DeleteAsync(role); 183 | } 184 | else 185 | { 186 | result = await RoleManager.DeleteAsync(role); 187 | } 188 | if (!result.Succeeded) 189 | { 190 | ModelState.AddModelError("", result.Errors.First()); 191 | return View(); 192 | } 193 | return RedirectToAction("Index"); 194 | } 195 | else 196 | { 197 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 198 | } 199 | } 200 | return View(); 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /IdentitySample/Controllers/UserAdminController.cs: -------------------------------------------------------------------------------- 1 | using IdentitySample.Models; 2 | using Microsoft.AspNet.Identity; 3 | using Microsoft.AspNet.Identity.Owin; 4 | using Microsoft.AspNet.Identity.EntityFramework; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Data.Entity; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Threading.Tasks; 11 | using System.Web; 12 | using System.Web.Mvc; 13 | 14 | namespace IdentitySample.Controllers 15 | { 16 | [Authorize(Roles = "Admin")] 17 | public class UsersAdminController : Controller 18 | { 19 | public UsersAdminController() 20 | { 21 | } 22 | 23 | public UsersAdminController(ApplicationUserManager userManager, ApplicationRoleManager roleManager) 24 | { 25 | UserManager = userManager; 26 | RoleManager = roleManager; 27 | } 28 | 29 | private ApplicationUserManager _userManager; 30 | public ApplicationUserManager UserManager 31 | { 32 | get 33 | { 34 | return _userManager ?? HttpContext.GetOwinContext().GetUserManager(); 35 | } 36 | private set 37 | { 38 | _userManager = value; 39 | } 40 | } 41 | 42 | private ApplicationRoleManager _roleManager; 43 | public ApplicationRoleManager RoleManager 44 | { 45 | get 46 | { 47 | return _roleManager ?? HttpContext.GetOwinContext().Get(); 48 | } 49 | private set 50 | { 51 | _roleManager = value; 52 | } 53 | } 54 | 55 | // 56 | // GET: /Users/ 57 | public async Task Index() 58 | { 59 | return View(await UserManager.Users.ToListAsync()); 60 | } 61 | 62 | // 63 | // GET: /Users/Details/5 64 | public async Task Details(int id) 65 | { 66 | if (id > 0) 67 | { 68 | // Process normally: 69 | var user = await UserManager.FindByIdAsync(id); 70 | ViewBag.RoleNames = await UserManager.GetRolesAsync(user.Id); 71 | return View(user); 72 | } 73 | // Return Error: 74 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 75 | } 76 | 77 | // 78 | // GET: /Users/Create 79 | public async Task Create() 80 | { 81 | //Get the list of Roles 82 | ViewBag.RoleId = new SelectList(await RoleManager.Roles.ToListAsync(), "Name", "Name"); 83 | return View(); 84 | } 85 | 86 | // 87 | // POST: /Users/Create 88 | [HttpPost] 89 | public async Task Create(RegisterViewModel userViewModel, params string[] selectedRoles) 90 | { 91 | if (ModelState.IsValid) 92 | { 93 | var user = new ApplicationUser { UserName = userViewModel.Email, Email = userViewModel.Email }; 94 | var adminresult = await UserManager.CreateAsync(user, userViewModel.Password); 95 | 96 | //Add User to the selected Roles 97 | if (adminresult.Succeeded) 98 | { 99 | if (selectedRoles != null) 100 | { 101 | var result = await UserManager.AddToRolesAsync(user.Id, selectedRoles); 102 | if (!result.Succeeded) 103 | { 104 | ModelState.AddModelError("", result.Errors.First()); 105 | ViewBag.RoleId = new SelectList(await RoleManager.Roles.ToListAsync(), "Name", "Name"); 106 | return View(); 107 | } 108 | } 109 | } 110 | else 111 | { 112 | ModelState.AddModelError("", adminresult.Errors.First()); 113 | ViewBag.RoleId = new SelectList(RoleManager.Roles, "Name", "Name"); 114 | return View(); 115 | 116 | } 117 | return RedirectToAction("Index"); 118 | } 119 | ViewBag.RoleId = new SelectList(RoleManager.Roles, "Name", "Name"); 120 | return View(); 121 | } 122 | 123 | // 124 | // GET: /Users/Edit/1 125 | public async Task Edit(int id) 126 | { 127 | if (id > 0) 128 | { 129 | var user = await UserManager.FindByIdAsync(id); 130 | if (user == null) 131 | { 132 | return HttpNotFound(); 133 | } 134 | 135 | var userRoles = await UserManager.GetRolesAsync(user.Id); 136 | return View(new EditUserViewModel() 137 | { 138 | Id = user.Id, 139 | Email = user.Email, 140 | RolesList = RoleManager.Roles.ToList().Select(x => new SelectListItem() 141 | { 142 | Selected = userRoles.Contains(x.Name), 143 | Text = x.Name, 144 | Value = x.Name 145 | }) 146 | }); 147 | } 148 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 149 | } 150 | 151 | // 152 | // POST: /Users/Edit/5 153 | [HttpPost] 154 | [ValidateAntiForgeryToken] 155 | public async Task Edit([Bind(Include = "Email,Id")] EditUserViewModel editUser, params string[] selectedRole) 156 | { 157 | if (ModelState.IsValid) 158 | { 159 | var user = await UserManager.FindByIdAsync(editUser.Id); 160 | if (user == null) 161 | { 162 | return HttpNotFound(); 163 | } 164 | 165 | user.UserName = editUser.Email; 166 | user.Email = editUser.Email; 167 | 168 | var userRoles = await UserManager.GetRolesAsync(user.Id); 169 | 170 | selectedRole = selectedRole ?? new string[] { }; 171 | 172 | var result = await UserManager.AddToRolesAsync(user.Id, selectedRole.Except(userRoles).ToArray()); 173 | 174 | if (!result.Succeeded) 175 | { 176 | ModelState.AddModelError("", result.Errors.First()); 177 | return View(); 178 | } 179 | result = await UserManager.RemoveFromRolesAsync(user.Id, userRoles.Except(selectedRole).ToArray()); 180 | 181 | if (!result.Succeeded) 182 | { 183 | ModelState.AddModelError("", result.Errors.First()); 184 | return View(); 185 | } 186 | return RedirectToAction("Index"); 187 | } 188 | ModelState.AddModelError("", "Something failed."); 189 | return View(); 190 | } 191 | 192 | // 193 | // GET: /Users/Delete/5 194 | public async Task Delete(int id) 195 | { 196 | if (id > 0) 197 | { 198 | var user = await UserManager.FindByIdAsync(id); 199 | if (user == null) 200 | { 201 | return HttpNotFound(); 202 | } 203 | return View(user); 204 | } 205 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 206 | } 207 | 208 | // 209 | // POST: /Users/Delete/5 210 | [HttpPost, ActionName("Delete")] 211 | [ValidateAntiForgeryToken] 212 | public async Task DeleteConfirmed(int id) 213 | { 214 | if (ModelState.IsValid) 215 | { 216 | if (id > 0) 217 | { 218 | var user = await UserManager.FindByIdAsync(id); 219 | if (user == null) 220 | { 221 | return HttpNotFound(); 222 | } 223 | var result = await UserManager.DeleteAsync(user); 224 | if (!result.Succeeded) 225 | { 226 | ModelState.AddModelError("", result.Errors.First()); 227 | return View(); 228 | } 229 | return RedirectToAction("Index"); 230 | } 231 | else 232 | { 233 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 234 | } 235 | } 236 | return View(); 237 | } 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /IdentitySample/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="IdentitySample.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /IdentitySample/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using IdentitySample.Models; 2 | using System.Data.Entity; 3 | using System.Web.Mvc; 4 | using System.Web.Optimization; 5 | using System.Web.Routing; 6 | 7 | namespace IdentitySample 8 | { 9 | // Note: For instructions on enabling IIS7 classic mode, 10 | // visit http://go.microsoft.com/?LinkId=301868 11 | public class MvcApplication : System.Web.HttpApplication 12 | { 13 | protected void Application_Start() 14 | { 15 | AreaRegistration.RegisterAllAreas(); 16 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 17 | RouteConfig.RegisterRoutes(RouteTable.Routes); 18 | BundleConfig.RegisterBundles(BundleTable.Bundles); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /IdentitySample/IdentitySample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | 2.0 10 | {42F22E71-1AFA-405D-9258-0583A9F01AB9} 11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 12 | Library 13 | Properties 14 | IdentitySample 15 | IdentitySample 16 | v4.5 17 | true 18 | 19 | 20 | 21 | 22 | ..\packages\WebGrease.1.5.2\lib 23 | 24 | 25 | true 26 | full 27 | false 28 | bin\ 29 | DEBUG;TRACE 30 | prompt 31 | 4 32 | 33 | 34 | pdbonly 35 | true 36 | bin\ 37 | TRACE 38 | prompt 39 | 4 40 | 41 | 42 | 43 | ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll 44 | 45 | 46 | ..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll 47 | 48 | 49 | ..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.SqlServer.dll 50 | 51 | 52 | ..\packages\Microsoft.AspNet.Identity.Core.2.1.0-alpha1\lib\net45\Microsoft.AspNet.Identity.Core.dll 53 | 54 | 55 | ..\packages\Microsoft.AspNet.Identity.EntityFramework.2.1.0-alpha1\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll 56 | 57 | 58 | ..\packages\Microsoft.AspNet.Identity.Owin.2.1.0-alpha1\lib\net45\Microsoft.AspNet.Identity.Owin.dll 59 | 60 | 61 | 62 | ..\packages\Microsoft.Owin.2.1.0\lib\net45\Microsoft.Owin.dll 63 | 64 | 65 | ..\packages\Microsoft.Owin.Host.SystemWeb.2.1.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll 66 | 67 | 68 | ..\packages\Microsoft.Owin.Security.2.1.0\lib\net45\Microsoft.Owin.Security.dll 69 | 70 | 71 | ..\packages\Microsoft.Owin.Security.Cookies.2.1.0\lib\net45\Microsoft.Owin.Security.Cookies.dll 72 | 73 | 74 | ..\packages\Microsoft.Owin.Security.Facebook.2.1.0\lib\net45\Microsoft.Owin.Security.Facebook.dll 75 | 76 | 77 | ..\packages\Microsoft.Owin.Security.Google.2.1.0\lib\net45\Microsoft.Owin.Security.Google.dll 78 | 79 | 80 | ..\packages\Microsoft.Owin.Security.MicrosoftAccount.2.1.0\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll 81 | 82 | 83 | ..\packages\Microsoft.Owin.Security.OAuth.2.1.0\lib\net45\Microsoft.Owin.Security.OAuth.dll 84 | 85 | 86 | ..\packages\Microsoft.Owin.Security.Twitter.2.1.0\lib\net45\Microsoft.Owin.Security.Twitter.dll 87 | 88 | 89 | True 90 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 91 | 92 | 93 | ..\packages\Newtonsoft.Json.5.0.8\lib\net45\Newtonsoft.Json.dll 94 | 95 | 96 | ..\packages\Owin.1.0\lib\net40\Owin.dll 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | False 111 | ..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll 112 | 113 | 114 | False 115 | ..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll 116 | 117 | 118 | ..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll 119 | 120 | 121 | False 122 | ..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll 123 | 124 | 125 | False 126 | ..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll 127 | 128 | 129 | False 130 | ..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll 131 | 132 | 133 | False 134 | ..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | ..\packages\WebGrease.1.5.2\lib\WebGrease.dll 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | Web.config 154 | 155 | 156 | Web.config 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | Global.asax 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 10.0 244 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | True 254 | True 255 | 55693 256 | / 257 | http://localhost:55693/ 258 | False 259 | False 260 | 261 | 262 | False 263 | 264 | 265 | 266 | 267 | 274 | -------------------------------------------------------------------------------- /IdentitySample/Models/AccountViewModels.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace IdentitySample.Models 5 | { 6 | public class ExternalLoginConfirmationViewModel 7 | { 8 | [Required] 9 | [Display(Name = "Email")] 10 | public string Email { get; set; } 11 | } 12 | 13 | public class ExternalLoginListViewModel 14 | { 15 | public string ReturnUrl { get; set; } 16 | } 17 | 18 | public class SendCodeViewModel 19 | { 20 | public string SelectedProvider { get; set; } 21 | public ICollection Providers { get; set; } 22 | public string ReturnUrl { get; set; } 23 | } 24 | 25 | public class VerifyCodeViewModel 26 | { 27 | [Required] 28 | public string Provider { get; set; } 29 | 30 | [Required] 31 | [Display(Name = "Code")] 32 | public string Code { get; set; } 33 | public string ReturnUrl { get; set; } 34 | 35 | [Display(Name = "Remember this browser?")] 36 | public bool RememberBrowser { get; set; } 37 | } 38 | 39 | public class ForgotViewModel 40 | { 41 | [Required] 42 | [Display(Name = "Email")] 43 | public string Email { get; set; } 44 | } 45 | 46 | public class LoginViewModel 47 | { 48 | [Required] 49 | [Display(Name = "Email")] 50 | [EmailAddress] 51 | public string Email { get; set; } 52 | 53 | [Required] 54 | [DataType(DataType.Password)] 55 | [Display(Name = "Password")] 56 | public string Password { get; set; } 57 | 58 | [Display(Name = "Remember me?")] 59 | public bool RememberMe { get; set; } 60 | } 61 | 62 | public class RegisterViewModel 63 | { 64 | [Required] 65 | [EmailAddress] 66 | [Display(Name = "Email")] 67 | public string Email { get; set; } 68 | 69 | [Required] 70 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 71 | [DataType(DataType.Password)] 72 | [Display(Name = "Password")] 73 | public string Password { get; set; } 74 | 75 | [DataType(DataType.Password)] 76 | [Display(Name = "Confirm password")] 77 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 78 | public string ConfirmPassword { get; set; } 79 | } 80 | 81 | public class ResetPasswordViewModel 82 | { 83 | [Required] 84 | [EmailAddress] 85 | [Display(Name = "Email")] 86 | public string Email { get; set; } 87 | 88 | [Required] 89 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 90 | [DataType(DataType.Password)] 91 | [Display(Name = "Password")] 92 | public string Password { get; set; } 93 | 94 | [DataType(DataType.Password)] 95 | [Display(Name = "Confirm password")] 96 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 97 | public string ConfirmPassword { get; set; } 98 | 99 | public string Code { get; set; } 100 | } 101 | 102 | public class ForgotPasswordViewModel 103 | { 104 | [Required] 105 | [EmailAddress] 106 | [Display(Name = "Email")] 107 | public string Email { get; set; } 108 | } 109 | } -------------------------------------------------------------------------------- /IdentitySample/Models/AdminViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.Web.Mvc; 4 | 5 | namespace IdentitySample.Models 6 | { 7 | public class RoleViewModel 8 | { 9 | public int Id { get; set; } 10 | [Required(AllowEmptyStrings = false)] 11 | [Display(Name = "RoleName")] 12 | public string Name { get; set; } 13 | } 14 | 15 | public class EditUserViewModel 16 | { 17 | public int Id { get; set; } 18 | 19 | [Required(AllowEmptyStrings = false)] 20 | [Display(Name = "Email")] 21 | [EmailAddress] 22 | public string Email { get; set; } 23 | 24 | public IEnumerable RolesList { get; set; } 25 | } 26 | } -------------------------------------------------------------------------------- /IdentitySample/Models/IdentityModels.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity; 2 | using Microsoft.AspNet.Identity.EntityFramework; 3 | using System.Data.Entity; 4 | using System.Security.Claims; 5 | using System.Threading.Tasks; 6 | using System; 7 | 8 | namespace IdentitySample.Models 9 | { 10 | public class ApplicationUserLogin : IdentityUserLogin { } 11 | public class ApplicationUserClaim : IdentityUserClaim { } 12 | public class ApplicationUserRole : IdentityUserRole { } 13 | 14 | public class ApplicationRole : IdentityRole, IRole 15 | { 16 | public string Description { get; set; } 17 | 18 | public ApplicationRole() : base() { } 19 | public ApplicationRole(string name) 20 | : this() 21 | { 22 | this.Name = name; 23 | } 24 | 25 | public ApplicationRole(string name, string description) 26 | : this(name) 27 | { 28 | this.Description = description; 29 | } 30 | } 31 | 32 | 33 | public class ApplicationUser : IdentityUser, IUser 34 | { 35 | public async Task 36 | GenerateUserIdentityAsync(UserManager manager) 37 | { 38 | var userIdentity = await manager 39 | .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); 40 | return userIdentity; 41 | } 42 | } 43 | 44 | 45 | public class ApplicationDbContext 46 | : IdentityDbContext 48 | { 49 | public ApplicationDbContext() 50 | : base("DefaultConnection") 51 | { 52 | } 53 | 54 | static ApplicationDbContext() 55 | { 56 | Database.SetInitializer(new ApplicationDbInitializer()); 57 | } 58 | 59 | public static ApplicationDbContext Create() 60 | { 61 | return new ApplicationDbContext(); 62 | } 63 | } 64 | 65 | 66 | public class ApplicationUserStore : 67 | UserStore, IUserStore, IDisposable 69 | { 70 | public ApplicationUserStore() 71 | : this(new IdentityDbContext()) 72 | { 73 | base.DisposeContext = true; 74 | } 75 | 76 | public ApplicationUserStore(DbContext context) 77 | : base(context) 78 | { 79 | } 80 | } 81 | 82 | 83 | public class ApplicationRoleStore 84 | : RoleStore, 85 | IQueryableRoleStore, 86 | IRoleStore, IDisposable 87 | { 88 | public ApplicationRoleStore() 89 | : base(new IdentityDbContext()) 90 | { 91 | base.DisposeContext = true; 92 | } 93 | 94 | public ApplicationRoleStore(DbContext context) 95 | : base(context) 96 | { 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /IdentitySample/Models/ManageViewModels.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity; 2 | using Microsoft.Owin.Security; 3 | using System.Collections.Generic; 4 | using System.ComponentModel.DataAnnotations; 5 | 6 | namespace IdentitySample.Models 7 | { 8 | public class IndexViewModel 9 | { 10 | public bool HasPassword { get; set; } 11 | public IList Logins { get; set; } 12 | public string PhoneNumber { get; set; } 13 | public bool TwoFactor { get; set; } 14 | public bool BrowserRemembered { get; set; } 15 | } 16 | 17 | public class ManageLoginsViewModel 18 | { 19 | public IList CurrentLogins { get; set; } 20 | public IList OtherLogins { get; set; } 21 | } 22 | 23 | public class FactorViewModel 24 | { 25 | public string Purpose { get; set; } 26 | } 27 | 28 | public class SetPasswordViewModel 29 | { 30 | [Required] 31 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 32 | [DataType(DataType.Password)] 33 | [Display(Name = "New password")] 34 | public string NewPassword { get; set; } 35 | 36 | [DataType(DataType.Password)] 37 | [Display(Name = "Confirm new password")] 38 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 39 | public string ConfirmPassword { get; set; } 40 | } 41 | 42 | public class ChangePasswordViewModel 43 | { 44 | [Required] 45 | [DataType(DataType.Password)] 46 | [Display(Name = "Current password")] 47 | public string OldPassword { get; set; } 48 | 49 | [Required] 50 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 51 | [DataType(DataType.Password)] 52 | [Display(Name = "New password")] 53 | public string NewPassword { get; set; } 54 | 55 | [DataType(DataType.Password)] 56 | [Display(Name = "Confirm new password")] 57 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 58 | public string ConfirmPassword { get; set; } 59 | } 60 | 61 | 62 | public class AddPhoneNumberViewModel 63 | { 64 | [Required] 65 | [Phone] 66 | [Display(Name = "Phone Number")] 67 | public string Number { get; set; } 68 | } 69 | 70 | public class VerifyPhoneNumberViewModel 71 | { 72 | [Required] 73 | [Display(Name = "Code")] 74 | public string Code { get; set; } 75 | 76 | [Required] 77 | [Phone] 78 | [Display(Name = "Phone Number")] 79 | public string PhoneNumber { get; set; } 80 | } 81 | 82 | public class ConfigureTwoFactorViewModel 83 | { 84 | public string SelectedProvider { get; set; } 85 | public ICollection Providers { get; set; } 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /IdentitySample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("IdentitySample")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("IdentitySample")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("60583fe5-93e5-40e0-bb74-ee684d8d5410")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /IdentitySample/Scripts/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /* 16 | ** Unobtrusive validation support library for jQuery and jQuery Validate 17 | ** Copyright (C) Microsoft Corporation. All rights reserved. 18 | */ 19 | (function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a("
  • ").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this);b.data("validator").resetForm();b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(c){var b=a(c),d=b.data(e),f=a.proxy(n,c);if(!d){d={options:{errorClass:"input-validation-error",errorElement:"span",errorPlacement:a.proxy(m,c),invalidHandler:a.proxy(l,c),messages:{},rules:{},success:a.proxy(k,c)},attachValidation:function(){b.unbind("reset."+e,f).bind("reset."+e,f).validate(this.options)},validate:function(){b.validate();return b.valid()}};b.data(e,d)}return d}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(b){var c=a(b).parents("form").andSelf().add(a(b).find("form")).filter("form");a(b).find(":input").filter("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});c.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){return a(b.form).find(":input").filter("[name='"+f(c)+"']").val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery); -------------------------------------------------------------------------------- /IdentitySample/Scripts/respond.js: -------------------------------------------------------------------------------- 1 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 2 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ 3 | window.matchMedia = window.matchMedia || (function(doc, undefined){ 4 | 5 | var bool, 6 | docElem = doc.documentElement, 7 | refNode = docElem.firstElementChild || docElem.firstChild, 8 | // fakeBody required for 9 | fakeBody = doc.createElement('body'), 10 | div = doc.createElement('div'); 11 | 12 | div.id = 'mq-test-1'; 13 | div.style.cssText = "position:absolute;top:-100em"; 14 | fakeBody.style.background = "none"; 15 | fakeBody.appendChild(div); 16 | 17 | return function(q){ 18 | 19 | div.innerHTML = '­'; 20 | 21 | docElem.insertBefore(fakeBody, refNode); 22 | bool = div.offsetWidth == 42; 23 | docElem.removeChild(fakeBody); 24 | 25 | return { matches: bool, media: q }; 26 | }; 27 | 28 | })(document); 29 | 30 | 31 | 32 | 33 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 34 | (function( win ){ 35 | //exposed namespace 36 | win.respond = {}; 37 | 38 | //define update even in native-mq-supporting browsers, to avoid errors 39 | respond.update = function(){}; 40 | 41 | //expose media query support flag for external use 42 | respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches; 43 | 44 | //if media queries are supported, exit here 45 | if( respond.mediaQueriesSupported ){ return; } 46 | 47 | //define vars 48 | var doc = win.document, 49 | docElem = doc.documentElement, 50 | mediastyles = [], 51 | rules = [], 52 | appendedEls = [], 53 | parsedSheets = {}, 54 | resizeThrottle = 30, 55 | head = doc.getElementsByTagName( "head" )[0] || docElem, 56 | base = doc.getElementsByTagName( "base" )[0], 57 | links = head.getElementsByTagName( "link" ), 58 | requestQueue = [], 59 | 60 | //loop stylesheets, send text content to translate 61 | ripCSS = function(){ 62 | var sheets = links, 63 | sl = sheets.length, 64 | i = 0, 65 | //vars for loop: 66 | sheet, href, media, isCSS; 67 | 68 | for( ; i < sl; i++ ){ 69 | sheet = sheets[ i ], 70 | href = sheet.href, 71 | media = sheet.media, 72 | isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet"; 73 | 74 | //only links plz and prevent re-parsing 75 | if( !!href && isCSS && !parsedSheets[ href ] ){ 76 | // selectivizr exposes css through the rawCssText expando 77 | if (sheet.styleSheet && sheet.styleSheet.rawCssText) { 78 | translate( sheet.styleSheet.rawCssText, href, media ); 79 | parsedSheets[ href ] = true; 80 | } else { 81 | if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) 82 | || href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){ 83 | requestQueue.push( { 84 | href: href, 85 | media: media 86 | } ); 87 | } 88 | } 89 | } 90 | } 91 | makeRequests(); 92 | }, 93 | 94 | //recurse through request queue, get css text 95 | makeRequests = function(){ 96 | if( requestQueue.length ){ 97 | var thisRequest = requestQueue.shift(); 98 | 99 | ajax( thisRequest.href, function( styles ){ 100 | translate( styles, thisRequest.href, thisRequest.media ); 101 | parsedSheets[ thisRequest.href ] = true; 102 | makeRequests(); 103 | } ); 104 | } 105 | }, 106 | 107 | //find media blocks in css text, convert to style blocks 108 | translate = function( styles, href, media ){ 109 | var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ), 110 | ql = qs && qs.length || 0, 111 | //try to get CSS path 112 | href = href.substring( 0, href.lastIndexOf( "/" )), 113 | repUrls = function( css ){ 114 | return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" ); 115 | }, 116 | useMedia = !ql && media, 117 | //vars used in loop 118 | i = 0, 119 | j, fullq, thisq, eachq, eql; 120 | 121 | //if path exists, tack on trailing slash 122 | if( href.length ){ href += "/"; } 123 | 124 | //if no internal queries exist, but media attr does, use that 125 | //note: this currently lacks support for situations where a media attr is specified on a link AND 126 | //its associated stylesheet has internal CSS media queries. 127 | //In those cases, the media attribute will currently be ignored. 128 | if( useMedia ){ 129 | ql = 1; 130 | } 131 | 132 | 133 | for( ; i < ql; i++ ){ 134 | j = 0; 135 | 136 | //media attr 137 | if( useMedia ){ 138 | fullq = media; 139 | rules.push( repUrls( styles ) ); 140 | } 141 | //parse for styles 142 | else{ 143 | fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1; 144 | rules.push( RegExp.$2 && repUrls( RegExp.$2 ) ); 145 | } 146 | 147 | eachq = fullq.split( "," ); 148 | eql = eachq.length; 149 | 150 | for( ; j < eql; j++ ){ 151 | thisq = eachq[ j ]; 152 | mediastyles.push( { 153 | media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all", 154 | rules : rules.length - 1, 155 | hasquery: thisq.indexOf("(") > -1, 156 | minw : thisq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ), 157 | maxw : thisq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ) 158 | } ); 159 | } 160 | } 161 | 162 | applyMedia(); 163 | }, 164 | 165 | lastCall, 166 | 167 | resizeDefer, 168 | 169 | // returns the value of 1em in pixels 170 | getEmValue = function() { 171 | var ret, 172 | div = doc.createElement('div'), 173 | body = doc.body, 174 | fakeUsed = false; 175 | 176 | div.style.cssText = "position:absolute;font-size:1em;width:1em"; 177 | 178 | if( !body ){ 179 | body = fakeUsed = doc.createElement( "body" ); 180 | body.style.background = "none"; 181 | } 182 | 183 | body.appendChild( div ); 184 | 185 | docElem.insertBefore( body, docElem.firstChild ); 186 | 187 | ret = div.offsetWidth; 188 | 189 | if( fakeUsed ){ 190 | docElem.removeChild( body ); 191 | } 192 | else { 193 | body.removeChild( div ); 194 | } 195 | 196 | //also update eminpx before returning 197 | ret = eminpx = parseFloat(ret); 198 | 199 | return ret; 200 | }, 201 | 202 | //cached container for 1em value, populated the first time it's needed 203 | eminpx, 204 | 205 | //enable/disable styles 206 | applyMedia = function( fromResize ){ 207 | var name = "clientWidth", 208 | docElemProp = docElem[ name ], 209 | currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp, 210 | styleBlocks = {}, 211 | lastLink = links[ links.length-1 ], 212 | now = (new Date()).getTime(); 213 | 214 | //throttle resize calls 215 | if( fromResize && lastCall && now - lastCall < resizeThrottle ){ 216 | clearTimeout( resizeDefer ); 217 | resizeDefer = setTimeout( applyMedia, resizeThrottle ); 218 | return; 219 | } 220 | else { 221 | lastCall = now; 222 | } 223 | 224 | for( var i in mediastyles ){ 225 | var thisstyle = mediastyles[ i ], 226 | min = thisstyle.minw, 227 | max = thisstyle.maxw, 228 | minnull = min === null, 229 | maxnull = max === null, 230 | em = "em"; 231 | 232 | if( !!min ){ 233 | min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 234 | } 235 | if( !!max ){ 236 | max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 237 | } 238 | 239 | // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true 240 | if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){ 241 | if( !styleBlocks[ thisstyle.media ] ){ 242 | styleBlocks[ thisstyle.media ] = []; 243 | } 244 | styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] ); 245 | } 246 | } 247 | 248 | //remove any existing respond style element(s) 249 | for( var i in appendedEls ){ 250 | if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){ 251 | head.removeChild( appendedEls[ i ] ); 252 | } 253 | } 254 | 255 | //inject active styles, grouped by media type 256 | for( var i in styleBlocks ){ 257 | var ss = doc.createElement( "style" ), 258 | css = styleBlocks[ i ].join( "\n" ); 259 | 260 | ss.type = "text/css"; 261 | ss.media = i; 262 | 263 | //originally, ss was appended to a documentFragment and sheets were appended in bulk. 264 | //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one! 265 | head.insertBefore( ss, lastLink.nextSibling ); 266 | 267 | if ( ss.styleSheet ){ 268 | ss.styleSheet.cssText = css; 269 | } 270 | else { 271 | ss.appendChild( doc.createTextNode( css ) ); 272 | } 273 | 274 | //push to appendedEls to track for later removal 275 | appendedEls.push( ss ); 276 | } 277 | }, 278 | //tweaked Ajax functions from Quirksmode 279 | ajax = function( url, callback ) { 280 | var req = xmlHttp(); 281 | if (!req){ 282 | return; 283 | } 284 | req.open( "GET", url, true ); 285 | req.onreadystatechange = function () { 286 | if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){ 287 | return; 288 | } 289 | callback( req.responseText ); 290 | } 291 | if ( req.readyState == 4 ){ 292 | return; 293 | } 294 | req.send( null ); 295 | }, 296 | //define ajax obj 297 | xmlHttp = (function() { 298 | var xmlhttpmethod = false; 299 | try { 300 | xmlhttpmethod = new XMLHttpRequest(); 301 | } 302 | catch( e ){ 303 | xmlhttpmethod = new ActiveXObject( "Microsoft.XMLHTTP" ); 304 | } 305 | return function(){ 306 | return xmlhttpmethod; 307 | }; 308 | })(); 309 | 310 | //translate CSS 311 | ripCSS(); 312 | 313 | //expose update for re-running respond later on 314 | respond.update = ripCSS; 315 | 316 | //adjust on resize 317 | function callMedia(){ 318 | applyMedia( true ); 319 | } 320 | if( win.addEventListener ){ 321 | win.addEventListener( "resize", callMedia, false ); 322 | } 323 | else if( win.attachEvent ){ 324 | win.attachEvent( "onresize", callMedia ); 325 | } 326 | })(this); 327 | -------------------------------------------------------------------------------- /IdentitySample/Scripts/respond.min.js: -------------------------------------------------------------------------------- 1 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 2 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ 3 | window.matchMedia=window.matchMedia||(function(e,f){var c,a=e.documentElement,b=a.firstElementChild||a.firstChild,d=e.createElement("body"),g=e.createElement("div");g.id="mq-test-1";g.style.cssText="position:absolute;top:-100em";d.style.background="none";d.appendChild(g);return function(h){g.innerHTML='­';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document); 4 | 5 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 6 | (function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this); -------------------------------------------------------------------------------- /IdentitySample/Startup.cs: -------------------------------------------------------------------------------- 1 | using Owin; 2 | 3 | namespace IdentitySample 4 | { 5 | public partial class Startup 6 | { 7 | public void Configuration(IAppBuilder app) 8 | { 9 | ConfigureAuth(app); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/ConfirmEmail.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Confirm Email"; 3 | } 4 | 5 |

    @ViewBag.Title.

    6 |
    7 |

    8 | Thank you for confirming your email. Please @Html.ActionLink("Click here to Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" }) 9 |

    10 |
    11 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/DisplayEmail.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "DEMO purpose Email Link"; 3 | } 4 |

    @ViewBag.Title.

    5 |

    6 | Please check your email and confirm your email address. 7 |

    8 |

    9 | For DEMO only: You can click this link to confirm the email: link 10 | Please change this code to register an email service in IdentityConfig to send an email. 11 |

    12 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/ExternalLoginConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.ExternalLoginConfirmationViewModel 2 | @{ 3 | ViewBag.Title = "Register"; 4 | } 5 |

    @ViewBag.Title.

    6 |

    Associate your @ViewBag.LoginProvider account.

    7 | 8 | @using (Html.BeginForm("ExternalLoginConfirmation", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 | 12 |

    Association Form

    13 |
    14 | @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 15 |

    16 | You've successfully authenticated with @ViewBag.LoginProvider. 17 | Please enter a user name for this site below and click the Register button to finish 18 | logging in. 19 |

    20 |
    21 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 22 |
    23 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 24 | @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" }) 25 |
    26 |
    27 |
    28 |
    29 | 30 |
    31 |
    32 | } 33 | 34 | @section Scripts { 35 | @Scripts.Render("~/bundles/jqueryval") 36 | } 37 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/ExternalLoginFailure.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Login Failure"; 3 | } 4 | 5 |
    6 |

    @ViewBag.Title.

    7 |

    Unsuccessful login with service.

    8 |
    9 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/ForgotPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.ForgotPasswordViewModel 2 | @{ 3 | ViewBag.Title = "Forgot your password?"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("ForgotPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Enter your email.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 |
    15 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 18 |
    19 |
    20 |
    21 |
    22 | 23 |
    24 |
    25 | } 26 | 27 | @section Scripts { 28 | @Scripts.Render("~/bundles/jqueryval") 29 | } 30 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/ForgotPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Forgot Password Confirmation"; 3 | } 4 | 5 |
    6 |

    @ViewBag.Title.

    7 |
    8 |
    9 |

    10 | Please check your email to reset your password. 11 |

    12 |

    13 | For DEMO only: You can click this link to reset password: link 14 | Please change this code to register an email service in IdentityConfig to send an email. 15 |

    16 |
    17 | 18 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.LoginViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Log in"; 5 | } 6 | 7 |

    @ViewBag.Title.

    8 |
    9 |
    10 |
    11 | @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) { 12 | @Html.AntiForgeryToken() 13 |

    Use a local account to log in.

    14 |
    15 | @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 16 |
    17 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 18 |
    19 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 20 | @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" }) 21 |
    22 |
    23 |
    24 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 25 |
    26 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 27 | @Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" }) 28 |
    29 |
    30 |
    31 |
    32 |
    33 | @Html.CheckBoxFor(m => m.RememberMe) 34 | @Html.LabelFor(m => m.RememberMe) 35 |
    36 |
    37 |
    38 |
    39 |
    40 | 41 |
    42 |
    43 |

    44 | @Html.ActionLink("Register a new user?", "Register") 45 |

    46 |

    47 | @Html.ActionLink("Forget your password?", "ForgotPassword") 48 |

    49 | } 50 |
    51 |
    52 |
    53 |
    54 | @Html.Partial("_ExternalLoginsListPartial", new IdentitySample.Models.ExternalLoginListViewModel { ReturnUrl = ViewBag.ReturnUrl }) 55 |
    56 |
    57 |
    58 | @section Scripts { 59 | @Scripts.Render("~/bundles/jqueryval") 60 | } -------------------------------------------------------------------------------- /IdentitySample/Views/Account/Register.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.RegisterViewModel 2 | @{ 3 | ViewBag.Title = "Register"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Create a new account.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 |
    15 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 18 |
    19 |
    20 |
    21 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 22 |
    23 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 24 |
    25 |
    26 |
    27 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 28 |
    29 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 30 |
    31 |
    32 |
    33 |
    34 | 35 |
    36 |
    37 | } 38 | 39 | @section Scripts { 40 | @Scripts.Render("~/bundles/jqueryval") 41 | } 42 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/ResetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.ResetPasswordViewModel 2 | @{ 3 | ViewBag.Title = "Reset password"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Reset your password.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 | @Html.HiddenFor(model => model.Code) 15 |
    16 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 17 |
    18 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 19 |
    20 |
    21 |
    22 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 23 |
    24 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 25 |
    26 |
    27 |
    28 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 29 |
    30 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 31 |
    32 |
    33 |
    34 |
    35 | 36 |
    37 |
    38 | } 39 | 40 | @section Scripts { 41 | @Scripts.Render("~/bundles/jqueryval") 42 | } 43 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/ResetPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Reset password confirmation"; 3 | } 4 | 5 |
    6 |

    @ViewBag.Title.

    7 |
    8 |
    9 |

    10 | Your password has been reset. Please @Html.ActionLink("click here to log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" }) 11 |

    12 |
    13 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/SendCode.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.SendCodeViewModel 2 | @{ 3 | ViewBag.Title = "Send Verification Code"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("SendCode", "Account", new { ReturnUrl = Model.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) { 9 | @Html.AntiForgeryToken() 10 |
    11 |
    12 | Two Factor Authentication Provider: 13 | @Html.DropDownListFor(model => model.SelectedProvider, Model.Providers) 14 | 15 |
    16 |
    17 | } 18 | 19 | @section Scripts { 20 | @Scripts.Render("~/bundles/jqueryval") 21 | } 22 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/VerifyCode.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.VerifyCodeViewModel 2 | @{ 3 | ViewBag.Title = "Enter Verification Code"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("VerifyCode", "Account", new { ReturnUrl = Model.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) { 9 | @Html.AntiForgeryToken() 10 | @Html.ValidationSummary("", new { @class = "text-danger" }) 11 | @Html.Hidden("provider", @Model.Provider) 12 |

    @ViewBag.Status

    13 |
    14 |
    15 | @Html.LabelFor(m => m.Code, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.TextBoxFor(m => m.Code, new { @class = "form-control" }) 18 |
    19 |
    20 |
    21 |
    22 |
    23 | @Html.CheckBoxFor(m => m.RememberBrowser) 24 | @Html.LabelFor(m => m.RememberBrowser) 25 |
    26 |
    27 |
    28 |
    29 |
    30 | 31 |
    32 |
    33 | } 34 | 35 | @section Scripts { 36 | @Scripts.Render("~/bundles/jqueryval") 37 | } 38 | -------------------------------------------------------------------------------- /IdentitySample/Views/Account/_ExternalLoginsListPartial.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.ExternalLoginListViewModel 2 | @using Microsoft.Owin.Security 3 | 4 |

    Use another service to log in.

    5 |
    6 | @{ 7 | var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes(); 8 | if (loginProviders.Count() == 0) { 9 |
    10 |

    11 | There are no external authentication services configured. See this article 12 | for details on setting up this ASP.NET application to support logging in via external services. 13 |

    14 |
    15 | } 16 | else { 17 | using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = Model.ReturnUrl })) { 18 | @Html.AntiForgeryToken() 19 |
    20 |

    21 | @foreach (AuthenticationDescription p in loginProviders) { 22 | 23 | } 24 |

    25 |
    26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /IdentitySample/Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "About"; 3 | } 4 |
    5 |

    @ViewBag.Title.

    6 |

    @ViewBag.Message

    7 |
    8 |
    9 |
    10 |

    Use this area to provide additional information.

    11 |
    12 |
    -------------------------------------------------------------------------------- /IdentitySample/Views/Home/Contact.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Contact"; 3 | } 4 |
    5 |

    @ViewBag.Title.

    6 |

    @ViewBag.Message

    7 |
    8 |
    9 |
    10 | One Microsoft Way
    11 | Redmond, WA 98052-6399
    12 | P: 13 | 425.555.0100 14 |
    15 | 16 |
    17 | Support: Support@example.com
    18 | Marketing: Marketing@example.com 19 |
    20 |
    -------------------------------------------------------------------------------- /IdentitySample/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Home Page"; 3 | } 4 | 5 |
    6 |

    ASP.NET Identity

    7 |

    ASP.NET Identity is the membership system for ASP.NET apps. Following are the features of ASP.NET Identity in this sample application.

    8 |

    Learn more »

    9 |
    10 | 11 |
    12 |
    13 |
    14 |
    Initialize ASP.NET Identity
    15 |
    16 | You can initialize ASP.NET Identity when the application starts. Since ASP.NET Identity is Entity Framework based in this sample, 17 | you can create DatabaseInitializer which is configured to get called each time the app starts. 18 | Please look in App_Start\IdentityConfig.cs 19 | This code shows the following 20 |
      21 |
    • When should the Initializer run and when should the database be created
    • 22 |
    • Create Admin user
    • 23 |
    • Create Admin role
    • 24 |
    • Add Admin user to Admin role
    • 25 |
    26 |
    27 |
    28 |
    29 |
    30 |
    31 |
    Add profile data for the user
    32 |
    33 | Please follow this tutorial. 34 | 35 |
      36 |
    • Add profile information in the Users Table
    • 37 |
    • Look in Models\IdentityModels.cs for examples
    • 38 |
    39 |
    40 |
    41 |
    42 |
    43 |
    44 |
    Validation
    45 |
    46 | When you create a User using a username or password, the Identity system performs validation on the username and password, and the passwords are hashed before they are 47 | stored in the database. You can customize the validation by changing some of the properties of the validators such as Turn alphanumeric on/off, set minimum password length 48 | or you can write your own custom validators and register them with the UserManager. 49 |
    50 |
    51 |
    52 |
    53 |
    54 |
    Register a user and login
    55 |
    56 | Click @Html.ActionLink("Register", "Register", "Account") and see the code in AccountController.cs and Register Action. 57 | Click @Html.ActionLink("Log in", "Login", "Account") and see the code in AccountController.cs and Login Action. 58 |
    59 |
    60 |
    61 |
    62 |
    63 |
    Social Logins
    64 |
    65 | You can the support so that users can login using their Facebook, Google, Twitter, Microsoft Account and more. 66 |
    67 |
    68 | 76 |
    77 |
    78 |
    79 |
    80 |
    81 |
    Basic User Management
    82 |
    83 | Do Create, Update, List and Delete Users. 84 | Assign a Role to a User. 85 | Only Users In Role Admin can access this page. This uses the [Authorize(Roles = "Admin")] on the UserAdmin controller. 86 |
    87 |
    88 |
    89 |
    90 |
    91 |
    Basic Role Management
    92 |
    93 | Do Create, Update, List and Delete Roles. 94 | Only Users In Role Admin can access this page. This authorization is doen by using the [Authorize(Roles = "Admin")] on the RolesAdmin controller. 95 |
    96 |
    97 |
    98 |
    99 |
    100 |
    Account Confirmation
    101 |
    102 | When you register a new account, you will be sent an email confirmation. 103 | You can use an email service such as SendGrid which integrate nicely with Windows Azure and requires no configuration or 104 | set up an SMTP server to send email. 105 | You can send email using the EmailService which is registered in App_Start\IdentityConfig.cs 106 |
    107 |
    108 |
    109 |
    110 |
    111 |
    Two-Factor Authentication
    112 |
    113 | This sample shows how you can use Two-Factor authentication. This sample has a SMS and email service registered where you can send SMS or email for sending the security code. 114 | You can add more two-factor authentication factors such as QR codes and plug them into ASP.NET Identity. 115 |
      116 |
    • 117 | You can use a SMS using Twilio or use any means of sending SMS. Please read for more details on using Twilio. 118 | You can send SMS using the SmsService which is registered in App_Start\IdentityConfig.cs 119 |
    • 120 |
    • 121 | You can use an email service such as SendGrid or 122 | set up an SMTP server to send email. 123 | You can send email using the EmailService which is registered in App_Start\IdentityConfig.cs 124 |
    • 125 | 126 |
    • 127 | When you login, you can add a phone number by clicking the Manage page. 128 |
    • 129 |
    • 130 | Once you add a phone number and have the Phone service hooked to send a SMS, you will get a code through SMS to confirm your phone number. 131 |
    • 132 |
    • 133 | In the Manage page, you can turn on Two-Factor authentication. 134 |
    • 135 |
    • 136 | When you logout and login, after you enter the username and password, you will get an option of how to get the security code to use for two-factor authentication. 137 |
    • 138 |
    • 139 | You can copy the code from your SMS or email and enter in the form to login. 140 |
    • 141 |
    • 142 | The sample also shows how to protect against Brute force attacks against two-factor codes. When you enter a code incorrectly for 5 times then you will be 143 | lockedout for 5 min before you can enter a new code. These settings can be configured in App_Start\IdentityConfig.cs by setting DefaultAccountLockoutTimeSpan and MaxFailedAccessAttemptsBeforeLockout on the UserManager. 144 |
    • 145 |
    • 146 | If the machine you are browsing this website is your own machine, you can choose to check the "Remember Me" option after you enter the code. 147 | This option will remember you forever on this machine and will not ask you for the two-factor authentication, the next time when you login to the website. 148 | You can change your "Remember Me" settings for two-factor authentication in the Manage page. 149 |
    • 150 |
    151 |
    152 |
    153 |
    154 |
    155 |
    156 |
    Account Lockout
    157 |
    158 | Provide a way to Lockout out the user if the user enters their password or two-factor codes incorrectly. 159 | The number of invalid attempts and the timespan for the users are locked out can be configured. 160 | A developer can optionally turn off Account Lockout for certain user accounts should they need to. 161 |
    162 |
      163 |
    • Account LockOut settings can be configured in the UserManager in IdentityConfig.cs
    • 164 |
    165 |
    166 |
    167 |
    168 |
    169 |
    Security Token provider
    170 |
    171 | Support a way to regenerate the Security Token for the user in cases when the User changes there password or any other security related information such as removing an associated login(such as Facebook, Google, Microsoft Account etc). 172 | This is needed to ensure that any tokens generated with the old password are invalidated. In the sample project, if you change the users password then a new token is generated for the user and any previous tokens are invalidated. 173 | This feature provides an extra layer of security to your application since when you change your password, you will be logged out from everywhere (all other browsers) where you have logged into this application. 174 |
    175 |
    176 |
      177 |
    • The provider is registered when you add CookieAuthentication in StartupAuth to your application.
    • 178 |
    179 |
    180 |
    181 |
    182 |
    183 |
    184 |
    Password Reset
    185 |
    186 | Allows the user to reset their passwords if they have forgotten their password. In this sample users need to confirm their email before they can reset their passwords. 187 |
    188 |
    189 |
    190 |
    191 |
    192 |
    Custom Storage providers
    193 |
    194 | You can extend ASP.NET Identity to write your own custom storage provider for storing the ASP.NET Identity system and user data 195 | in a persistance system of your choice such as MondoDb, RavenDb, Azure Table Storage etc. 196 |
    197 |
    198 | 205 |
    206 |
    207 |
    208 |
    209 |
    210 |
    Documentation
    211 |
    212 | 229 |
    230 |
    231 |
    232 |
    -------------------------------------------------------------------------------- /IdentitySample/Views/Manage/AddPhoneNumber.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.AddPhoneNumberViewModel 2 | @{ 3 | ViewBag.Title = "Add Phone Number"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("AddPhoneNumber", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Add a phone number.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 |
    15 | @Html.LabelFor(m => m.Number, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.TextBoxFor(m => m.Number, new { @class = "form-control" }) 18 |
    19 |
    20 |
    21 |
    22 | 23 |
    24 |
    25 | } 26 | 27 | @section Scripts { 28 | @Scripts.Render("~/bundles/jqueryval") 29 | } 30 | -------------------------------------------------------------------------------- /IdentitySample/Views/Manage/ChangePassword.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.ChangePasswordViewModel 2 | @{ 3 | ViewBag.Title = "Change Password"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("ChangePassword", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Change Password Form

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 |
    15 | @Html.LabelFor(m => m.OldPassword, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.PasswordFor(m => m.OldPassword, new { @class = "form-control" }) 18 |
    19 |
    20 |
    21 | @Html.LabelFor(m => m.NewPassword, new { @class = "col-md-2 control-label" }) 22 |
    23 | @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" }) 24 |
    25 |
    26 |
    27 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 28 |
    29 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 30 |
    31 |
    32 | 33 |
    34 |
    35 | 36 |
    37 |
    38 | } 39 | @section Scripts { 40 | @Scripts.Render("~/bundles/jqueryval") 41 | } -------------------------------------------------------------------------------- /IdentitySample/Views/Manage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.IndexViewModel 2 | @{ 3 | ViewBag.Title = "Manage your account"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 |

    @ViewBag.StatusMessage

    8 |
    9 |
    10 |

    11 | @if (Model.HasPassword) 12 | { 13 | @Html.ActionLink("Change your password", "ChangePassword") 14 | } 15 | else 16 | { 17 | @Html.ActionLink("Pick a password", "SetPassword") 18 | } 19 |

    20 |

    21 | Phone Number: @(Model.PhoneNumber ?? "None") [ 22 | @if (Model.PhoneNumber != null) 23 | { 24 | @Html.ActionLink("Change", "AddPhoneNumber") 25 | @:  |  26 | @Html.ActionLink("Remove", "RemovePhoneNumber") 27 | } 28 | else 29 | { 30 | @Html.ActionLink("Add", "AddPhoneNumber") 31 | } 32 | ] 33 |

    34 |

    35 | External Logins: @Model.Logins.Count 36 | @Html.ActionLink("[Manage]", "ManageLogins") 37 |

    38 | @if (Model.TwoFactor) 39 | { 40 |
    41 |

    42 | Two factor is currently enabled: 43 | 44 |

    45 |
    46 | } 47 | else 48 | { 49 |
    50 |

    51 | Two factor is currently disabled: 52 | 53 |

    54 |
    55 | } 56 | @if (Model.BrowserRemembered) 57 | { 58 |
    59 |

    60 | Browser is curently remembered for two factor: 61 | 62 |

    63 |
    64 | } 65 | else 66 | { 67 |
    68 |

    69 | Browser is curently not remembered for two factor: 70 | 71 |

    72 |
    73 | } 74 |
    75 |
    76 | -------------------------------------------------------------------------------- /IdentitySample/Views/Manage/ManageLogins.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.ManageLoginsViewModel 2 | @using Microsoft.Owin.Security 3 | @{ 4 | ViewBag.Title = "Manage your external logins"; 5 | } 6 | 7 |

    @ViewBag.Title.

    8 | 9 |

    @ViewBag.StatusMessage

    10 | @if (Model.CurrentLogins.Count > 0) 11 | { 12 |

    Registered Logins

    13 | 14 | 15 | @foreach (var account in Model.CurrentLogins) 16 | { 17 | 18 | 19 | 37 | 38 | } 39 | 40 |
    @account.LoginProvider 20 | @if (ViewBag.ShowRemoveButton) 21 | { 22 | using (Html.BeginForm("RemoveLogin", "Manage")) 23 | { 24 | @Html.AntiForgeryToken() 25 |
    26 | @Html.Hidden("loginProvider", account.LoginProvider) 27 | @Html.Hidden("providerKey", account.ProviderKey) 28 | 29 |
    30 | } 31 | } 32 | else 33 | { 34 | @:   35 | } 36 |
    41 | } 42 | @if (Model.OtherLogins.Count > 0) 43 | { 44 |

    Add another service to log in.

    45 |
    46 | using (Html.BeginForm("LinkLogin", "Manage")) 47 | { 48 | @Html.AntiForgeryToken() 49 |
    50 |

    51 | @foreach (AuthenticationDescription p in Model.OtherLogins) 52 | { 53 | 54 | } 55 |

    56 |
    57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /IdentitySample/Views/Manage/SetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.SetPasswordViewModel 2 | 3 |

    4 | You do not have a local username/password for this site. Add a local 5 | account so you can log in without an external login. 6 |

    7 | 8 | @using (Html.BeginForm("SetPassword", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 | 12 |

    Create Local Login

    13 |
    14 | @Html.ValidationSummary("", new { @class = "text-danger" }) 15 |
    16 | @Html.LabelFor(m => m.NewPassword, new { @class = "col-md-2 control-label" }) 17 |
    18 | @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" }) 19 |
    20 |
    21 |
    22 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 23 |
    24 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 25 |
    26 |
    27 |
    28 |
    29 | 30 |
    31 |
    32 | } 33 | @section Scripts { 34 | @Scripts.Render("~/bundles/jqueryval") 35 | } -------------------------------------------------------------------------------- /IdentitySample/Views/Manage/VerifyPhoneNumber.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.VerifyPhoneNumberViewModel 2 | @{ 3 | ViewBag.Title = "Verify Phone Number"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("VerifyPhoneNumber", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 | @Html.Hidden("phoneNumber", @Model.PhoneNumber) 12 |

    Add a phone number.

    13 |
    @ViewBag.Status
    14 |
    15 | @Html.ValidationSummary("", new { @class = "text-danger" }) 16 |
    17 | @Html.LabelFor(m => m.Code, new { @class = "col-md-2 control-label" }) 18 |
    19 | @Html.TextBoxFor(m => m.Code, new { @class = "form-control" }) 20 |
    21 |
    22 |
    23 |
    24 | 25 |
    26 |
    27 | } 28 | 29 | @section Scripts { 30 | @Scripts.Render("~/bundles/jqueryval") 31 | } 32 | -------------------------------------------------------------------------------- /IdentitySample/Views/RolesAdmin/Create.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.RoleViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Create"; 5 | } 6 | 7 |

    Create.

    8 | 9 | 10 | @using (Html.BeginForm()) 11 | { 12 | @Html.AntiForgeryToken() 13 | 14 |
    15 |

    Role.

    16 |
    17 | @Html.ValidationSummary(true) 18 | 19 |
    20 | @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" }) 21 |
    22 | @Html.TextBoxFor(model => model.Name, new { @class = "form-control" }) 23 | @Html.ValidationMessageFor(model => model.Name) 24 |
    25 |
    26 | 27 |
    28 |
    29 | 30 |
    31 |
    32 |
    33 | } 34 | 35 |
    36 | @Html.ActionLink("Back to List", "Index") 37 |
    38 | 39 | @section Scripts { 40 | @Scripts.Render("~/bundles/jqueryval") 41 | } 42 | -------------------------------------------------------------------------------- /IdentitySample/Views/RolesAdmin/Delete.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.ApplicationRole 2 | 3 | @{ 4 | ViewBag.Title = "Delete"; 5 | } 6 | 7 |

    Delete.

    8 | 9 |

    Are you sure you want to delete this Role?

    10 |

    Deleting this Role will remove all users from this role. It will not delete the users.

    11 |
    12 |

    Role.

    13 |
    14 |
    15 |
    16 | @Html.DisplayNameFor(model => model.Name) 17 |
    18 | 19 |
    20 | @Html.DisplayFor(model => model.Name) 21 |
    22 |
    23 | @using (Html.BeginForm()) 24 | { 25 | @Html.AntiForgeryToken() 26 | 27 |
    28 | | 29 | @Html.ActionLink("Back to List", "Index") 30 |
    31 | } 32 |
    33 | -------------------------------------------------------------------------------- /IdentitySample/Views/RolesAdmin/Details.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.ApplicationRole 2 | 3 | @{ 4 | ViewBag.Title = "Details"; 5 | } 6 | 7 |

    Details.

    8 | 9 |
    10 |

    Roles.

    11 |
    12 |
    13 |
    14 | @Html.DisplayNameFor(model => model.Name) 15 |
    16 |
    17 | @Html.DisplayFor(model => model.Name) 18 |
    19 |
    20 |
    21 |

    List of users in this role

    22 | @if (ViewBag.UserCount == 0) 23 | { 24 |
    25 |

    No users found in this role.

    26 | } 27 | 28 | 29 | 30 | @foreach (var item in ViewBag.Users) 31 | { 32 | 33 | 36 | 37 | } 38 |
    34 | @item.UserName 35 |
    39 |

    40 | @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) | 41 | @Html.ActionLink("Back to List", "Index") 42 |

    43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /IdentitySample/Views/RolesAdmin/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.RoleViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Edit"; 5 | } 6 | 7 |

    Edit.

    8 | 9 | 10 | @using (Html.BeginForm()) 11 | { 12 | @Html.AntiForgeryToken() 13 | 14 |
    15 |

    Roles.

    16 |
    17 | @Html.ValidationSummary(true) 18 | @Html.HiddenFor(model => model.Id) 19 | 20 |
    21 | @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" }) 22 |
    23 | @Html.TextBoxFor(model => model.Name, new { @class = "form-control" }) 24 | @Html.ValidationMessageFor(model => model.Name) 25 |
    26 |
    27 | 28 |
    29 |
    30 | 31 |
    32 |
    33 |
    34 | } 35 | 36 |
    37 | @Html.ActionLink("Back to List", "Index") 38 |
    39 | 40 | @section Scripts { 41 | @Scripts.Render("~/bundles/jqueryval") 42 | } 43 | -------------------------------------------------------------------------------- /IdentitySample/Views/RolesAdmin/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IEnumerable 2 | 3 | @{ 4 | ViewBag.Title = "Index"; 5 | } 6 | 7 |

    Index

    8 | 9 |

    10 | @Html.ActionLink("Create New", "Create") 11 |

    12 | 13 | 14 | 17 | 20 | 21 | 22 | @foreach (var item in Model) 23 | { 24 | 25 | 28 | 33 | 34 | } 35 | 36 |
    15 | @Html.DisplayNameFor(model => model.Name) 16 | 18 | 19 |
    26 | @Html.DisplayFor(modelItem => item.Name) 27 | 29 | @Html.ActionLink("Edit", "Edit", new { id = item.Id }) | 30 | @Html.ActionLink("Details", "Details", new { id = item.Id }) | 31 | @Html.ActionLink("Delete", "Delete", new { id = item.Id }) 32 |
    37 | -------------------------------------------------------------------------------- /IdentitySample/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model System.Web.Mvc.HandleErrorInfo 2 | 3 | @{ 4 | ViewBag.Title = "Error"; 5 | } 6 | 7 |
    8 |

    Error.

    9 |

    An error occurred while processing your request.

    10 |
    11 | -------------------------------------------------------------------------------- /IdentitySample/Views/Shared/Lockout.cshtml: -------------------------------------------------------------------------------- 1 | @model System.Web.Mvc.HandleErrorInfo 2 | 3 | @{ 4 | ViewBag.Title = "Locked Out"; 5 | } 6 | 7 |
    8 |

    Locked out.

    9 |

    This account has been locked out, please try again later.

    10 |
    11 | -------------------------------------------------------------------------------- /IdentitySample/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title - My ASP.NET Application 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | 12 | 37 |
    38 | @RenderBody() 39 |
    40 |
    41 |

    © @DateTime.Now.Year - My ASP.NET Application

    42 |
    43 |
    44 | 45 | @Scripts.Render("~/bundles/jquery") 46 | @Scripts.Render("~/bundles/bootstrap") 47 | @RenderSection("scripts", required: false) 48 | 49 | 50 | -------------------------------------------------------------------------------- /IdentitySample/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNet.Identity 2 | @if (Request.IsAuthenticated) { 3 | using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" })) { 4 | @Html.AntiForgeryToken() 5 | 6 | 12 | } 13 | } 14 | else { 15 | 19 | } 20 | -------------------------------------------------------------------------------- /IdentitySample/Views/UsersAdmin/Create.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.RegisterViewModel 2 | @{ 3 | ViewBag.Title = "Create"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("Create", "UsersAdmin", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Create a new account.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-error" }) 14 |
    15 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 18 |
    19 |
    20 |
    21 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 22 |
    23 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 24 |
    25 |
    26 |
    27 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 28 |
    29 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 30 |
    31 |
    32 |
    33 | 36 |
    37 | @foreach (var item in (SelectList)ViewBag.RoleId) 38 | { 39 | 40 | @Html.Label(item.Value, new { @class = "control-label" }) 41 | } 42 |
    43 |
    44 |
    45 |
    46 | 47 |
    48 |
    49 | } 50 | 51 | @section Scripts { 52 | @Scripts.Render("~/bundles/jqueryval") 53 | } 54 | -------------------------------------------------------------------------------- /IdentitySample/Views/UsersAdmin/Delete.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.ApplicationUser 2 | 3 | @{ 4 | ViewBag.Title = "Delete"; 5 | } 6 | 7 |

    Delete.

    8 | 9 |

    Are you sure you want to delete this User?

    10 |
    11 |

    User.

    12 |
    13 |
    14 |
    15 | @Html.DisplayNameFor(model => model.UserName) 16 |
    17 | 18 |
    19 | @Html.DisplayFor(model => model.UserName) 20 |
    21 |
    22 | 23 | @using (Html.BeginForm()) { 24 | @Html.AntiForgeryToken() 25 | 26 |
    27 | | 28 | @Html.ActionLink("Back to List", "Index") 29 |
    30 | } 31 |
    32 | -------------------------------------------------------------------------------- /IdentitySample/Views/UsersAdmin/Details.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.ApplicationUser 2 | 3 | @{ 4 | ViewBag.Title = "Details"; 5 | } 6 | 7 |

    Details.

    8 | 9 |
    10 |

    User

    11 |
    12 |
    13 |
    14 | @Html.DisplayNameFor(model => model.UserName) 15 |
    16 |
    17 | @Html.DisplayFor(model => model.UserName) 18 |
    19 |
    20 |
    21 |

    List of roles for this user

    22 | @if (ViewBag.RoleNames.Count == 0) 23 | { 24 |
    25 |

    No roles found for this user.

    26 | } 27 | 28 | 29 | 30 | @foreach (var item in ViewBag.RoleNames) 31 | { 32 | 33 | 36 | 37 | } 38 |
    34 | @item 35 |
    39 |

    40 | @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) | 41 | @Html.ActionLink("Back to List", "Index") 42 |

    43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /IdentitySample/Views/UsersAdmin/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model IdentitySample.Models.EditUserViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Edit"; 5 | } 6 | 7 |

    Edit.

    8 | 9 | 10 | @using (Html.BeginForm()) { 11 | @Html.AntiForgeryToken() 12 | 13 |
    14 |

    Edit User Form.

    15 |
    16 | @Html.ValidationSummary(true) 17 | @Html.HiddenFor(model => model.Id) 18 | 19 |
    20 | @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" }) 21 |
    22 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 23 | @Html.ValidationMessageFor(model => model.Email) 24 |
    25 |
    26 |
    27 | @Html.Label("Roles", new { @class = "control-label col-md-2" }) 28 | 29 | @foreach (var item in Model.RolesList) 30 | { 31 | 32 | @Html.Label(item.Value, new { @class = "control-label" }) 33 | } 34 | 35 |
    36 | 37 |
    38 |
    39 | 40 |
    41 |
    42 |
    43 | } 44 | 45 |
    46 | @Html.ActionLink("Back to List", "Index") 47 |
    48 | 49 | @section Scripts { 50 | @Scripts.Render("~/bundles/jqueryval") 51 | } 52 | -------------------------------------------------------------------------------- /IdentitySample/Views/UsersAdmin/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IEnumerable 2 | 3 | @{ 4 | ViewBag.Title = "Index"; 5 | } 6 | 7 |

    Index

    8 | 9 |

    10 | @Html.ActionLink("Create New", "Create") 11 |

    12 | 13 | 14 | 17 | 20 | 21 | 22 | @foreach (var item in Model) 23 | { 24 | 25 | 28 | 33 | 34 | } 35 | 36 |
    15 | @Html.DisplayNameFor(model => model.UserName) 16 | 18 | 19 |
    26 | @Html.DisplayFor(modelItem => item.UserName) 27 | 29 | @Html.ActionLink("Edit", "Edit", new { id = item.Id }) | 30 | @Html.ActionLink("Details", "Details", new { id = item.Id }) | 31 | @Html.ActionLink("Delete", "Delete", new { id = item.Id }) 32 |
    37 | -------------------------------------------------------------------------------- /IdentitySample/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
    7 |
    8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /IdentitySample/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } -------------------------------------------------------------------------------- /IdentitySample/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /IdentitySample/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /IdentitySample/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 |
    10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /IdentitySample/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TypecastException/AspNet-Identity-2-With-Integer-Keys/0eac85fe3f9b9ec4939b95ea81710adee816a9a8/IdentitySample/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /IdentitySample/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TypecastException/AspNet-Identity-2-With-Integer-Keys/0eac85fe3f9b9ec4939b95ea81710adee816a9a8/IdentitySample/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /IdentitySample/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TypecastException/AspNet-Identity-2-With-Integer-Keys/0eac85fe3f9b9ec4939b95ea81710adee816a9a8/IdentitySample/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /IdentitySample/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AspNet-Identity-2-With-Integer-Keys 2 | =================================== 3 | 4 | This project approches a little more advanced customization of the ASP.NET Identity 2.0 RTM framework. The project accompannies a blog post which walks through the basics of implementing integer keys instead of the default string keys which Identity uses out-of-the-box. The project starts with the Identity Samples project available from Nuget. 5 | 6 | The post which accompanies this example can be found at [ASP.NET Identity 2.0 Extending Identity Models and Using Integer Keys Instead of Strings](http://typecastexception.com/post/2014/07/13/ASPNET-Identity-20-Extending-Identity-Models-and-Using-Integer-Keys-Instead-of-Strings.aspx) 7 | 8 | If you find errors, or have suggestions for improvement, please feel free to open an issue, and/or submit a pull request. 9 | --------------------------------------------------------------------------------