├── .gitignore ├── .nuget ├── NuGet.Config ├── NuGet.exe └── NuGet.targets ├── .tfignore ├── AspNetRoleCustomization.sln ├── AspNetRoleCustomization ├── App_Start │ ├── BundleConfig.cs │ ├── FilterConfig.cs │ ├── RouteConfig.cs │ └── Startup.Auth.cs ├── AspNetRoleCustomization.csproj ├── Content │ ├── Site.css │ ├── bootstrap.css │ └── bootstrap.min.css ├── Controllers │ ├── AccountController.cs │ ├── GroupsController.cs │ ├── HomeController.cs │ └── RolesController.cs ├── Global.asax ├── Global.asax.cs ├── MigrateConfigText.txt ├── Migrations │ ├── 201402092222180_init.Designer.cs │ ├── 201402092222180_init.cs │ ├── 201402092222180_init.resx │ └── Configuration.cs ├── Models │ ├── AccountViewModels.cs │ ├── ApplicationDbContext.cs │ ├── ApplicationRole.cs │ ├── ApplicationRoleGroup.cs │ ├── ApplicationUser.cs │ ├── ApplicationUserGroup.cs │ ├── Group.cs │ ├── IdentityManager.cs │ └── RoleManagementViewModels.cs ├── Project_Readme.html ├── Properties │ └── AssemblyInfo.cs ├── Scripts │ ├── _references.js │ ├── 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 │ │ ├── Delete.cshtml │ │ ├── Edit.cshtml │ │ ├── Index.cshtml │ │ ├── Login.cshtml │ │ ├── Manage.cshtml │ │ ├── Register.cshtml │ │ ├── UserGroups.cshtml │ │ ├── UserPermissions.cshtml │ │ ├── _ChangePasswordPartial.cshtml │ │ └── _SetPasswordPartial.cshtml │ ├── Groups │ │ ├── Create.cshtml │ │ ├── Delete.cshtml │ │ ├── Details.cshtml │ │ ├── Edit.cshtml │ │ ├── GroupRoles.cshtml │ │ └── Index.cshtml │ ├── Home │ │ ├── About.cshtml │ │ ├── Contact.cshtml │ │ └── Index.cshtml │ ├── Roles │ │ ├── Create.cshtml │ │ ├── Delete.cshtml │ │ ├── Details.cshtml │ │ ├── Edit.cshtml │ │ └── Index.cshtml │ ├── Shared │ │ ├── EditorTemplates │ │ │ ├── SelectGroupEditorViewModel.cshtml │ │ │ └── SelectRoleEditorViewModel.cshtml │ │ ├── Error.cshtml │ │ ├── _Layout.cshtml │ │ └── _LoginPartial.cshtml │ ├── Web.config │ └── _ViewStart.cshtml ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── favicon.ico ├── 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*/ 32 | App_Data*/ -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xivSolutions/AspNetAdvancedRoleManagement/032526e015a5fd03d2da6e8812624da59b624a08/.nuget/NuGet.exe -------------------------------------------------------------------------------- /.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) 32 | 33 | 34 | 35 | 36 | $(SolutionDir).nuget 37 | packages.config 38 | 39 | 40 | 41 | 42 | $(NuGetToolsPath)\NuGet.exe 43 | @(PackageSource) 44 | 45 | "$(NuGetExePath)" 46 | mono --runtime=v4.0.30319 $(NuGetExePath) 47 | 48 | $(TargetDir.Trim('\\')) 49 | 50 | -RequireConsent 51 | -NonInteractive 52 | 53 | "$(SolutionDir) " 54 | "$(SolutionDir)" 55 | 56 | 57 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 58 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 59 | 60 | 61 | 62 | RestorePackages; 63 | $(BuildDependsOn); 64 | 65 | 66 | 67 | 68 | $(BuildDependsOn); 69 | BuildPackage; 70 | 71 | 72 | 73 | 74 | 75 | 76 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | 98 | 100 | 101 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /.tfignore: -------------------------------------------------------------------------------- 1 | \.git -------------------------------------------------------------------------------- /AspNetRoleCustomization.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetRoleCustomization", "AspNetRoleCustomization\AspNetRoleCustomization.csproj", "{D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6DCF7BBA-8C8E-4E64-A6F0-3CB2A778DA69}" 9 | ProjectSection(SolutionItems) = preProject 10 | .nuget\NuGet.Config = .nuget\NuGet.Config 11 | .nuget\NuGet.exe = .nuget\NuGet.exe 12 | .nuget\NuGet.targets = .nuget\NuGet.targets 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA}.Release|Any CPU.Build.0 = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(SolutionProperties) = preSolution 27 | HideSolutionNode = FALSE 28 | EndGlobalSection 29 | EndGlobal 30 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/App_Start/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Optimization; 3 | 4 | namespace AspNetRoleCustomization 5 | { 6 | public class BundleConfig 7 | { 8 | // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 9 | public static void RegisterBundles(BundleCollection bundles) 10 | { 11 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include( 12 | "~/Scripts/jquery-{version}.js")); 13 | 14 | bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( 15 | "~/Scripts/jquery.validate*")); 16 | 17 | // Use the development version of Modernizr to develop with and learn from. Then, when you're 18 | // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. 19 | bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( 20 | "~/Scripts/modernizr-*")); 21 | 22 | bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( 23 | "~/Scripts/bootstrap.js", 24 | "~/Scripts/respond.js")); 25 | 26 | bundles.Add(new StyleBundle("~/Content/css").Include( 27 | "~/Content/bootstrap.css", 28 | "~/Content/site.css")); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | 4 | namespace AspNetRoleCustomization 5 | { 6 | public class FilterConfig 7 | { 8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 9 | { 10 | filters.Add(new HandleErrorAttribute()); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace AspNetRoleCustomization 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 | ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/App_Start/Startup.Auth.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity; 2 | using Microsoft.Owin; 3 | using Microsoft.Owin.Security.Cookies; 4 | using Owin; 5 | 6 | namespace AspNetRoleCustomization 7 | { 8 | public partial class Startup 9 | { 10 | // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 11 | public void ConfigureAuth(IAppBuilder app) 12 | { 13 | // Enable the application to use a cookie to store information for the signed in user 14 | app.UseCookieAuthentication(new CookieAuthenticationOptions 15 | { 16 | AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 17 | LoginPath = new PathString("/Account/Login") 18 | }); 19 | // Use a cookie to temporarily store information about a user logging in with a third party login provider 20 | app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); 21 | 22 | // Uncomment the following lines to enable logging in with third party login providers 23 | //app.UseMicrosoftAccountAuthentication( 24 | // clientId: "", 25 | // clientSecret: ""); 26 | 27 | //app.UseTwitterAuthentication( 28 | // consumerKey: "", 29 | // consumerSecret: ""); 30 | 31 | //app.UseFacebookAuthentication( 32 | // appId: "", 33 | // appSecret: ""); 34 | 35 | //app.UseGoogleAuthentication(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/AspNetRoleCustomization.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | 2.0 10 | {D7ADA016-6E82-4F70-B6CF-B687A3B6F6EA} 11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 12 | Library 13 | Properties 14 | AspNetRoleCustomization 15 | AspNetRoleCustomization 16 | v4.5 17 | false 18 | true 19 | 20 | 21 | 22 | 23 | ..\ 24 | true 25 | 26 | 27 | true 28 | full 29 | false 30 | bin\ 31 | DEBUG;TRACE 32 | prompt 33 | 4 34 | 35 | 36 | pdbonly 37 | true 38 | bin\ 39 | TRACE 40 | prompt 41 | 4 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | False 50 | ..\packages\Microsoft.AspNet.WebApi.Client.5.0.0\lib\net45\System.Net.Http.Formatting.dll 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | False 60 | ..\packages\Microsoft.AspNet.WebApi.Core.5.0.0\lib\net45\System.Web.Http.dll 61 | 62 | 63 | False 64 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.0.0\lib\net45\System.Web.Http.WebHost.dll 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | True 77 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 78 | 79 | 80 | 81 | 82 | 83 | 84 | True 85 | ..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.Helpers.dll 86 | 87 | 88 | True 89 | ..\packages\Microsoft.AspNet.Mvc.5.0.0\lib\net45\System.Web.Mvc.dll 90 | 91 | 92 | ..\packages\Microsoft.AspNet.Web.Optimization.1.1.1\lib\net40\System.Web.Optimization.dll 93 | 94 | 95 | True 96 | ..\packages\Microsoft.AspNet.Razor.3.0.0\lib\net45\System.Web.Razor.dll 97 | 98 | 99 | True 100 | ..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.WebPages.dll 101 | 102 | 103 | True 104 | ..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.WebPages.Deployment.dll 105 | 106 | 107 | True 108 | ..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.WebPages.Razor.dll 109 | 110 | 111 | True 112 | ..\packages\Newtonsoft.Json.5.0.6\lib\net45\Newtonsoft.Json.dll 113 | 114 | 115 | True 116 | ..\packages\WebGrease.1.5.2\lib\WebGrease.dll 117 | 118 | 119 | True 120 | ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll 121 | 122 | 123 | 124 | 125 | ..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.dll 126 | 127 | 128 | ..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.SqlServer.dll 129 | 130 | 131 | ..\packages\Microsoft.AspNet.Identity.Core.1.0.0\lib\net45\Microsoft.AspNet.Identity.Core.dll 132 | 133 | 134 | ..\packages\Microsoft.AspNet.Identity.Owin.1.0.0\lib\net45\Microsoft.AspNet.Identity.Owin.dll 135 | 136 | 137 | ..\packages\Microsoft.AspNet.Identity.EntityFramework.1.0.0\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll 138 | 139 | 140 | ..\packages\Owin.1.0\lib\net40\Owin.dll 141 | 142 | 143 | ..\packages\Microsoft.Owin.2.0.0\lib\net45\Microsoft.Owin.dll 144 | 145 | 146 | ..\packages\Microsoft.Owin.Host.SystemWeb.2.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll 147 | 148 | 149 | ..\packages\Microsoft.Owin.Security.2.0.0\lib\net45\Microsoft.Owin.Security.dll 150 | 151 | 152 | ..\packages\Microsoft.Owin.Security.Facebook.2.0.0\lib\net45\Microsoft.Owin.Security.Facebook.dll 153 | 154 | 155 | ..\packages\Microsoft.Owin.Security.Cookies.2.0.0\lib\net45\Microsoft.Owin.Security.Cookies.dll 156 | 157 | 158 | ..\packages\Microsoft.Owin.Security.OAuth.2.0.0\lib\net45\Microsoft.Owin.Security.OAuth.dll 159 | 160 | 161 | ..\packages\Microsoft.Owin.Security.Google.2.0.0\lib\net45\Microsoft.Owin.Security.Google.dll 162 | 163 | 164 | ..\packages\Microsoft.Owin.Security.Twitter.2.0.0\lib\net45\Microsoft.Owin.Security.Twitter.dll 165 | 166 | 167 | ..\packages\Microsoft.Owin.Security.MicrosoftAccount.2.0.0\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | Global.asax 181 | 182 | 183 | 184 | 201402092222180_init.cs 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 | Web.config 224 | 225 | 226 | Web.config 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 201402092222180_init.cs 274 | 275 | 276 | 277 | 10.0 278 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | True 291 | True 292 | 58980 293 | / 294 | http://localhost:58980/ 295 | False 296 | False 297 | 298 | 299 | False 300 | 301 | 302 | 303 | 304 | 305 | 311 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/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 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Controllers/AccountController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity; 2 | using Microsoft.AspNet.Identity.EntityFramework; 3 | using Microsoft.Owin.Security; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Web; 8 | using System.Web.Mvc; 9 | using AspNetRoleCustomization.Models; 10 | 11 | namespace AspNetRoleCustomization.Controllers 12 | { 13 | [Authorize] 14 | public class AccountController : Controller 15 | { 16 | private ApplicationDbContext _db = new ApplicationDbContext(); 17 | public UserManager UserManager { get; private set; } 18 | 19 | public AccountController() 20 | : this(new UserManager(new UserStore(new ApplicationDbContext()))) 21 | { 22 | } 23 | 24 | 25 | public AccountController(UserManager userManager) 26 | { 27 | UserManager = userManager; 28 | } 29 | 30 | 31 | [AllowAnonymous] 32 | public ActionResult Login(string returnUrl) 33 | { 34 | ViewBag.ReturnUrl = returnUrl; 35 | return View(); 36 | } 37 | 38 | 39 | [HttpPost] 40 | [AllowAnonymous] 41 | [ValidateAntiForgeryToken] 42 | public async Task Login(LoginViewModel model, string returnUrl) 43 | { 44 | if (ModelState.IsValid) 45 | { 46 | var user = await UserManager.FindAsync(model.UserName, model.Password); 47 | if (user != null) 48 | { 49 | await SignInAsync(user, model.RememberMe); 50 | return RedirectToLocal(returnUrl); 51 | } 52 | else 53 | { 54 | ModelState.AddModelError("", "Invalid username or password."); 55 | } 56 | } 57 | 58 | // If we got this far, something failed, redisplay form 59 | return View(model); 60 | } 61 | 62 | 63 | [Authorize(Roles = "Admin, EditUser")] 64 | public ActionResult Register() 65 | { 66 | return View(); 67 | } 68 | 69 | 70 | [HttpPost] 71 | [Authorize(Roles = "Admin, EditUser")] 72 | [ValidateAntiForgeryToken] 73 | public async Task Register(RegisterViewModel model) 74 | { 75 | if (ModelState.IsValid) 76 | { 77 | var user = model.GetUser(); 78 | var result = await UserManager.CreateAsync(user, model.Password); 79 | if (result.Succeeded) 80 | { 81 | return RedirectToAction("Index", "Account"); 82 | } 83 | 84 | } 85 | 86 | // If we got this far, something failed, redisplay form 87 | return View(model); 88 | } 89 | 90 | 91 | [Authorize(Roles = "Admin, EditUser")] 92 | public ActionResult Manage(ManageMessageId? message) 93 | { 94 | ViewBag.StatusMessage = 95 | message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." 96 | : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." 97 | : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." 98 | : message == ManageMessageId.Error ? "An error has occurred." 99 | : ""; 100 | ViewBag.HasLocalPassword = HasPassword(); 101 | ViewBag.ReturnUrl = Url.Action("Manage"); 102 | return View(); 103 | } 104 | 105 | 106 | [HttpPost] 107 | [ValidateAntiForgeryToken] 108 | [Authorize(Roles = "Admin, EditUser, ManageProfile")] 109 | public async Task Manage(ManageUserViewModel model) 110 | { 111 | bool hasPassword = HasPassword(); 112 | ViewBag.HasLocalPassword = hasPassword; 113 | ViewBag.ReturnUrl = Url.Action("Manage"); 114 | if (hasPassword) 115 | { 116 | if (ModelState.IsValid) 117 | { 118 | IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); 119 | if (result.Succeeded) 120 | { 121 | return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess }); 122 | } 123 | else 124 | { 125 | AddErrors(result); 126 | } 127 | } 128 | } 129 | else 130 | { 131 | // User does not have a password so remove any validation errors caused by a missing OldPassword field 132 | ModelState state = ModelState["OldPassword"]; 133 | if (state != null) 134 | { 135 | state.Errors.Clear(); 136 | } 137 | 138 | if (ModelState.IsValid) 139 | { 140 | IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword); 141 | if (result.Succeeded) 142 | { 143 | return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess }); 144 | } 145 | else 146 | { 147 | AddErrors(result); 148 | } 149 | } 150 | } 151 | 152 | // If we got this far, something failed, redisplay form 153 | return View(model); 154 | } 155 | 156 | 157 | [HttpPost] 158 | [ValidateAntiForgeryToken] 159 | public ActionResult LogOff() 160 | { 161 | AuthenticationManager.SignOut(); 162 | return RedirectToAction("Index", "Home"); 163 | } 164 | 165 | 166 | protected override void Dispose(bool disposing) 167 | { 168 | if (disposing && UserManager != null) 169 | { 170 | UserManager.Dispose(); 171 | UserManager = null; 172 | } 173 | base.Dispose(disposing); 174 | } 175 | 176 | 177 | [Authorize(Roles = "Admin, EditUser")] 178 | public ActionResult Index() 179 | { 180 | var users = _db.Users; 181 | var model = new List(); 182 | foreach (var user in users) 183 | { 184 | var u = new EditUserViewModel(user); 185 | model.Add(u); 186 | } 187 | return View(model); 188 | } 189 | 190 | 191 | [Authorize(Roles = "Admin, EditUser")] 192 | public ActionResult Edit(string id, ManageMessageId? Message = null) 193 | { 194 | var user = _db.Users.First(u => u.UserName == id); 195 | var model = new EditUserViewModel(user); 196 | ViewBag.MessageId = Message; 197 | return View(model); 198 | } 199 | 200 | 201 | [HttpPost] 202 | [Authorize(Roles = "Admin, EditUser")] 203 | [ValidateAntiForgeryToken] 204 | public async Task Edit(EditUserViewModel model) 205 | { 206 | if (ModelState.IsValid) 207 | { 208 | var user = _db.Users.First(u => u.UserName == model.UserName); 209 | user.FirstName = model.FirstName; 210 | user.LastName = model.LastName; 211 | user.Email = model.Email; 212 | _db.Entry(user).State = System.Data.Entity.EntityState.Modified; 213 | await _db.SaveChangesAsync(); 214 | return RedirectToAction("Index"); 215 | } 216 | 217 | // If we got this far, something failed, redisplay form 218 | return View(model); 219 | } 220 | 221 | 222 | [Authorize(Roles = "Admin, EditUser")] 223 | public ActionResult Delete(string id = null) 224 | { 225 | var user = _db.Users.First(u => u.UserName == id); 226 | var model = new EditUserViewModel(user); 227 | if (user == null) 228 | { 229 | return HttpNotFound(); 230 | } 231 | return View(model); 232 | } 233 | 234 | 235 | [HttpPost, ActionName("Delete")] 236 | [ValidateAntiForgeryToken] 237 | [Authorize(Roles = "Admin, EditUser")] 238 | public ActionResult DeleteConfirmed(string id) 239 | { 240 | var user = _db.Users.First(u => u.UserName == id); 241 | _db.Users.Remove(user); 242 | _db.SaveChanges(); 243 | return RedirectToAction("Index"); 244 | } 245 | 246 | 247 | [Authorize(Roles = "Admin, EditGroups")] 248 | public ActionResult UserGroups(string id) 249 | { 250 | var user = _db.Users.First(u => u.UserName == id); 251 | var model = new SelectUserGroupsViewModel(user); 252 | return View(model); 253 | } 254 | 255 | 256 | [HttpPost] 257 | [Authorize(Roles = "Admin, EditGroups")] 258 | [ValidateAntiForgeryToken] 259 | public ActionResult UserGroups(SelectUserGroupsViewModel model) 260 | { 261 | if (ModelState.IsValid) 262 | { 263 | var idManager = new IdentityManager(); 264 | var user = _db.Users.First(u => u.UserName == model.UserName); 265 | idManager.ClearUserGroups(user.Id); 266 | foreach (var group in model.Groups) 267 | { 268 | if (group.Selected) 269 | { 270 | idManager.AddUserToGroup(user.Id, group.GroupId); 271 | } 272 | } 273 | return RedirectToAction("index"); 274 | } 275 | return View(); 276 | } 277 | 278 | [Authorize(Roles = "Admin, ViewPermissions")] 279 | public ActionResult UserPermissions(string id) 280 | { 281 | var user = _db.Users.First(u => u.UserName == id); 282 | var model = new UserPermissionsViewModel(user); 283 | return View(model); 284 | } 285 | 286 | 287 | #region Helpers 288 | 289 | private IAuthenticationManager AuthenticationManager 290 | { 291 | get 292 | { 293 | return HttpContext.GetOwinContext().Authentication; 294 | } 295 | } 296 | 297 | 298 | private async Task SignInAsync(ApplicationUser user, bool isPersistent) 299 | { 300 | AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); 301 | var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); 302 | AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); 303 | } 304 | 305 | 306 | private void AddErrors(IdentityResult result) 307 | { 308 | foreach (var error in result.Errors) 309 | { 310 | ModelState.AddModelError("", error); 311 | } 312 | } 313 | 314 | 315 | private bool HasPassword() 316 | { 317 | var user = UserManager.FindById(User.Identity.GetUserId()); 318 | if (user != null) 319 | { 320 | return user.PasswordHash != null; 321 | } 322 | return false; 323 | } 324 | 325 | 326 | public enum ManageMessageId 327 | { 328 | ChangePasswordSuccess, 329 | SetPasswordSuccess, 330 | RemoveLoginSuccess, 331 | Error 332 | } 333 | 334 | 335 | private ActionResult RedirectToLocal(string returnUrl) 336 | { 337 | if (Url.IsLocalUrl(returnUrl)) 338 | { 339 | return Redirect(returnUrl); 340 | } 341 | else 342 | { 343 | return RedirectToAction("Index", "Home"); 344 | } 345 | } 346 | 347 | #endregion 348 | } 349 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Controllers/GroupsController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Data.Entity; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Web; 8 | using System.Web.Mvc; 9 | using AspNetRoleCustomization.Models; 10 | 11 | namespace AspNetRoleCustomization.Controllers 12 | { 13 | public class GroupsController : Controller 14 | { 15 | private ApplicationDbContext db = new ApplicationDbContext(); 16 | 17 | [Authorize(Roles = "Admin, ViewGroups")] 18 | public ActionResult Index() 19 | { 20 | return View(db.Groups.ToList()); 21 | } 22 | 23 | 24 | [Authorize(Roles = "Admin, ViewGroups")] 25 | public ActionResult Details(int? id) 26 | { 27 | if (id == null) 28 | { 29 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 30 | } 31 | Group group = db.Groups.Find(id); 32 | if (group == null) 33 | { 34 | return HttpNotFound(); 35 | } 36 | return View(group); 37 | } 38 | 39 | 40 | [Authorize(Roles = "Admin, ViewGroups")] 41 | public ActionResult Create() 42 | { 43 | return View(); 44 | } 45 | 46 | 47 | [Authorize(Roles = "Admin, GroupEditor")] 48 | [HttpPost] 49 | [ValidateAntiForgeryToken] 50 | public ActionResult Create([Bind(Include="Name")] Group group) 51 | { 52 | if (ModelState.IsValid) 53 | { 54 | db.Groups.Add(group); 55 | db.SaveChanges(); 56 | return RedirectToAction("Index"); 57 | } 58 | 59 | return View(group); 60 | } 61 | 62 | 63 | [Authorize(Roles = "Admin, GroupEditor")] 64 | public ActionResult Edit(int? id) 65 | { 66 | if (id == null) 67 | { 68 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 69 | } 70 | Group group = db.Groups.Find(id); 71 | if (group == null) 72 | { 73 | return HttpNotFound(); 74 | } 75 | return View(group); 76 | } 77 | 78 | 79 | [Authorize(Roles = "Admin, GroupEditor")] 80 | [HttpPost] 81 | [ValidateAntiForgeryToken] 82 | public ActionResult Edit([Bind(Include="Name")] Group group) 83 | { 84 | if (ModelState.IsValid) 85 | { 86 | db.Entry(group).State = EntityState.Modified; 87 | db.SaveChanges(); 88 | return RedirectToAction("Index"); 89 | } 90 | return View(group); 91 | } 92 | 93 | 94 | [Authorize(Roles = "Admin, GroupEditor")] 95 | public ActionResult Delete(int? id) 96 | { 97 | if (id == null) 98 | { 99 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 100 | } 101 | Group group = db.Groups.Find(id); 102 | if (group == null) 103 | { 104 | return HttpNotFound(); 105 | } 106 | return View(group); 107 | } 108 | 109 | 110 | [Authorize(Roles = "Admin, GroupEditor")] 111 | [HttpPost, ActionName("Delete")] 112 | [ValidateAntiForgeryToken] 113 | public ActionResult DeleteConfirmed(int id) 114 | { 115 | Group group = db.Groups.Find(id); 116 | db.Groups.Remove(group); 117 | db.SaveChanges(); 118 | return RedirectToAction("Index"); 119 | } 120 | 121 | 122 | [Authorize(Roles = "Admin, GroupEditor")] 123 | public ActionResult GroupRoles(int id) 124 | { 125 | var group = db.Groups.Find(id); 126 | var model = new SelectGroupRolesViewModel(group); 127 | return View(model); 128 | } 129 | 130 | 131 | [HttpPost] 132 | [Authorize(Roles = "Admin, GroupEditor")] 133 | [ValidateAntiForgeryToken] 134 | public ActionResult GroupRoles(SelectGroupRolesViewModel model) 135 | { 136 | if (ModelState.IsValid) 137 | { 138 | var idManager = new IdentityManager(); 139 | var Db = new ApplicationDbContext(); 140 | var group = Db.Groups.Find(model.GroupId); 141 | idManager.ClearGroupRoles(model.GroupId); 142 | 143 | // Add each selected role to this group: 144 | foreach (var role in model.Roles) 145 | { 146 | if (role.Selected) 147 | { 148 | idManager.AddRoleToGroup(group.Id, role.RoleName); 149 | } 150 | } 151 | return RedirectToAction("index"); 152 | } 153 | return View(); 154 | } 155 | 156 | 157 | protected override void Dispose(bool disposing) 158 | { 159 | if (disposing) 160 | { 161 | db.Dispose(); 162 | } 163 | base.Dispose(disposing); 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | 7 | namespace AspNetRoleCustomization.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | public ActionResult Index() 12 | { 13 | return View(); 14 | } 15 | 16 | public ActionResult About() 17 | { 18 | ViewBag.Message = "Your application description page."; 19 | 20 | return View(); 21 | } 22 | 23 | public ActionResult Contact() 24 | { 25 | ViewBag.Message = "Your contact page."; 26 | 27 | return View(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Controllers/RolesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Data.Entity; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Web; 8 | using System.Web.Mvc; 9 | using AspNetRoleCustomization.Models; 10 | 11 | namespace AspNetRoleCustomization.Controllers 12 | { 13 | public class RolesController : Controller 14 | { 15 | private ApplicationDbContext db = new ApplicationDbContext(); 16 | 17 | [Authorize(Roles = "Admin, ViewPermissions")] 18 | public ActionResult Index() 19 | { 20 | var roles = db.ApplicationRoles.ToList(); 21 | return View(db.ApplicationRoles.ToList()); 22 | } 23 | 24 | [Authorize(Roles = "Admin, SuperAdmin, ViewPermissions")] 25 | public ActionResult Details(string id) 26 | { 27 | if (id == null) 28 | { 29 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 30 | } 31 | ApplicationRole applicationrole = db.ApplicationRoles.Find(id); 32 | if (applicationrole == null) 33 | { 34 | return HttpNotFound(); 35 | } 36 | return View(applicationrole); 37 | } 38 | 39 | [Authorize(Roles = "Admin, EditPermissions")] 40 | public ActionResult Create() 41 | { 42 | return View(); 43 | } 44 | 45 | 46 | [HttpPost] 47 | [ValidateAntiForgeryToken] 48 | [Authorize(Roles = "Admin, EditPermissions")] 49 | public ActionResult Create([Bind(Include="Name,Description")] ApplicationRole applicationrole) 50 | { 51 | if (ModelState.IsValid) 52 | { 53 | db.Roles.Add(applicationrole); 54 | db.SaveChanges(); 55 | return RedirectToAction("Index"); 56 | } 57 | 58 | return View(applicationrole); 59 | } 60 | 61 | [Authorize(Roles = "Admin, EditPermissions")] 62 | public ActionResult Edit(string id) 63 | { 64 | if (id == null) 65 | { 66 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 67 | } 68 | ApplicationRole applicationrole = db.ApplicationRoles.Find(id); 69 | if (applicationrole == null) 70 | { 71 | return HttpNotFound(); 72 | } 73 | return View(applicationrole); 74 | } 75 | 76 | 77 | [HttpPost] 78 | [ValidateAntiForgeryToken] 79 | [Authorize(Roles = "Admin, EditPermissions")] 80 | public ActionResult Edit([Bind(Include="Id,Name,Description")] ApplicationRole applicationrole) 81 | { 82 | if (ModelState.IsValid) 83 | { 84 | db.Entry(applicationrole).State = EntityState.Modified; 85 | db.SaveChanges(); 86 | return RedirectToAction("Index"); 87 | } 88 | return View(applicationrole); 89 | } 90 | 91 | [Authorize(Roles = "Admin, EditPermissions")] 92 | public ActionResult Delete(string id) 93 | { 94 | if (id == null) 95 | { 96 | return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 97 | } 98 | ApplicationRole applicationrole = db.ApplicationRoles.Find(id); 99 | if (applicationrole == null) 100 | { 101 | return HttpNotFound(); 102 | } 103 | return View(applicationrole); 104 | } 105 | 106 | 107 | [HttpPost, ActionName("Delete")] 108 | [ValidateAntiForgeryToken] 109 | [Authorize(Roles = "Admin, EditPermissions")] 110 | public ActionResult DeleteConfirmed(string id) 111 | { 112 | ApplicationRole applicationrole = db.ApplicationRoles.Find(id); 113 | var idManager = new IdentityManager(); 114 | idManager.DeleteRole(id); 115 | return RedirectToAction("Index"); 116 | } 117 | 118 | protected override void Dispose(bool disposing) 119 | { 120 | if (disposing) 121 | { 122 | db.Dispose(); 123 | } 124 | base.Dispose(disposing); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="AspNetRoleCustomization.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Optimization; 7 | using System.Web.Routing; 8 | 9 | namespace AspNetRoleCustomization 10 | { 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 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/MigrateConfigText.txt: -------------------------------------------------------------------------------- 1 | using AspNetRoleCustomization.Models; 2 | using System.Data.Entity.Migrations; 3 | 4 | namespace AspNetRoleCustomization.Migrations 5 | { 6 | using System; 7 | using System.Data.Entity; 8 | using System.Data.Entity.Migrations; 9 | using System.Linq; 10 | 11 | internal sealed class Configuration : DbMigrationsConfiguration 12 | { 13 | public Configuration() 14 | { 15 | AutomaticMigrationsEnabled = true; 16 | } 17 | 18 | 19 | protected override void Seed(ApplicationDbContext context) 20 | { 21 | this.AddUserAndRoles(); 22 | } 23 | 24 | 25 | bool AddUserAndRoles() 26 | { 27 | bool success = false; 28 | 29 | var idManager = new IdentityManager(); 30 | success = idManager.CreateRole("Admin"); 31 | if (!success == true) return success; 32 | 33 | success = idManager.CreateRole("CanEdit"); 34 | if (!success == true) return success; 35 | 36 | success = idManager.CreateRole("User"); 37 | if (!success) return success; 38 | 39 | 40 | var newUser = new ApplicationUser() 41 | { 42 | UserName = "jatten", 43 | FirstName = "John", 44 | LastName = "Atten", 45 | Email = "jatten@typecastexception.com" 46 | }; 47 | 48 | // Be careful here - you will need to use a password which will 49 | // be valid under the password rules for the application, 50 | // or the process will abort: 51 | success = idManager.CreateUser(newUser, "Password1"); 52 | if (!success) return success; 53 | 54 | success = idManager.AddUserToRole(newUser.Id, "Admin"); 55 | if (!success) return success; 56 | 57 | success = idManager.AddUserToRole(newUser.Id, "CanEdit"); 58 | if (!success) return success; 59 | 60 | success = idManager.AddUserToRole(newUser.Id, "User"); 61 | if (!success) return success; 62 | 63 | return success; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Migrations/201402092222180_init.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | namespace AspNetRoleCustomization.Migrations 3 | { 4 | using System.CodeDom.Compiler; 5 | using System.Data.Entity.Migrations; 6 | using System.Data.Entity.Migrations.Infrastructure; 7 | using System.Resources; 8 | 9 | [GeneratedCode("EntityFramework.Migrations", "6.0.0-20911")] 10 | public sealed partial class init : IMigrationMetadata 11 | { 12 | private readonly ResourceManager Resources = new ResourceManager(typeof(init)); 13 | 14 | string IMigrationMetadata.Id 15 | { 16 | get { return "201402092222180_init"; } 17 | } 18 | 19 | string IMigrationMetadata.Source 20 | { 21 | get { return null; } 22 | } 23 | 24 | string IMigrationMetadata.Target 25 | { 26 | get { return Resources.GetString("Target"); } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Migrations/201402092222180_init.cs: -------------------------------------------------------------------------------- 1 | namespace AspNetRoleCustomization.Migrations 2 | { 3 | using System; 4 | using System.Data.Entity.Migrations; 5 | 6 | public partial class init : DbMigration 7 | { 8 | public override void Up() 9 | { 10 | CreateTable( 11 | "dbo.Groups", 12 | c => new 13 | { 14 | Id = c.Int(nullable: false, identity: true), 15 | Name = c.String(nullable: false), 16 | }) 17 | .PrimaryKey(t => t.Id); 18 | 19 | CreateTable( 20 | "dbo.ApplicationRoleGroups", 21 | c => new 22 | { 23 | RoleId = c.String(nullable: false, maxLength: 128), 24 | GroupId = c.Int(nullable: false), 25 | }) 26 | .PrimaryKey(t => new { t.RoleId, t.GroupId }) 27 | .ForeignKey("dbo.AspNetRoles", t => t.RoleId) 28 | .ForeignKey("dbo.Groups", t => t.GroupId, cascadeDelete: true) 29 | .Index(t => t.RoleId) 30 | .Index(t => t.GroupId); 31 | 32 | CreateTable( 33 | "dbo.IdentityRoles", 34 | c => new 35 | { 36 | Id = c.String(nullable: false, maxLength: 128), 37 | Name = c.String(), 38 | }) 39 | .PrimaryKey(t => t.Id); 40 | 41 | CreateTable( 42 | "dbo.IdentityUsers", 43 | c => new 44 | { 45 | Id = c.String(nullable: false, maxLength: 128), 46 | UserName = c.String(), 47 | PasswordHash = c.String(), 48 | SecurityStamp = c.String(), 49 | }) 50 | .PrimaryKey(t => t.Id); 51 | 52 | CreateTable( 53 | "dbo.AspNetUserClaims", 54 | c => new 55 | { 56 | Id = c.Int(nullable: false, identity: true), 57 | ClaimType = c.String(), 58 | ClaimValue = c.String(), 59 | User_Id = c.String(nullable: false, maxLength: 128), 60 | }) 61 | .PrimaryKey(t => t.Id) 62 | .ForeignKey("dbo.IdentityUsers", t => t.User_Id, cascadeDelete: true) 63 | .Index(t => t.User_Id); 64 | 65 | CreateTable( 66 | "dbo.AspNetUserLogins", 67 | c => new 68 | { 69 | UserId = c.String(nullable: false, maxLength: 128), 70 | LoginProvider = c.String(nullable: false, maxLength: 128), 71 | ProviderKey = c.String(nullable: false, maxLength: 128), 72 | }) 73 | .PrimaryKey(t => new { t.UserId, t.LoginProvider, t.ProviderKey }) 74 | .ForeignKey("dbo.IdentityUsers", t => t.UserId, cascadeDelete: true) 75 | .Index(t => t.UserId); 76 | 77 | CreateTable( 78 | "dbo.AspNetUserRoles", 79 | c => new 80 | { 81 | UserId = c.String(nullable: false, maxLength: 128), 82 | RoleId = c.String(nullable: false, maxLength: 128), 83 | }) 84 | .PrimaryKey(t => new { t.UserId, t.RoleId }) 85 | .ForeignKey("dbo.IdentityRoles", t => t.RoleId, cascadeDelete: true) 86 | .ForeignKey("dbo.IdentityUsers", t => t.UserId, cascadeDelete: true) 87 | .Index(t => t.RoleId) 88 | .Index(t => t.UserId); 89 | 90 | CreateTable( 91 | "dbo.ApplicationUserGroups", 92 | c => new 93 | { 94 | UserId = c.String(nullable: false, maxLength: 128), 95 | GroupId = c.Int(nullable: false), 96 | }) 97 | .PrimaryKey(t => new { t.UserId, t.GroupId }) 98 | .ForeignKey("dbo.Groups", t => t.GroupId, cascadeDelete: true) 99 | .ForeignKey("dbo.AspNetUsers", t => t.UserId) 100 | .Index(t => t.GroupId) 101 | .Index(t => t.UserId); 102 | 103 | CreateTable( 104 | "dbo.AspNetRoles", 105 | c => new 106 | { 107 | Id = c.String(nullable: false, maxLength: 128), 108 | Description = c.String(), 109 | }) 110 | .PrimaryKey(t => t.Id) 111 | .ForeignKey("dbo.IdentityRoles", t => t.Id) 112 | .Index(t => t.Id); 113 | 114 | CreateTable( 115 | "dbo.AspNetUsers", 116 | c => new 117 | { 118 | Id = c.String(nullable: false, maxLength: 128), 119 | FirstName = c.String(nullable: false), 120 | LastName = c.String(nullable: false), 121 | Email = c.String(nullable: false), 122 | }) 123 | .PrimaryKey(t => t.Id) 124 | .ForeignKey("dbo.IdentityUsers", t => t.Id) 125 | .Index(t => t.Id); 126 | 127 | } 128 | 129 | public override void Down() 130 | { 131 | DropForeignKey("dbo.AspNetUsers", "Id", "dbo.IdentityUsers"); 132 | DropForeignKey("dbo.AspNetRoles", "Id", "dbo.IdentityRoles"); 133 | DropForeignKey("dbo.ApplicationUserGroups", "UserId", "dbo.AspNetUsers"); 134 | DropForeignKey("dbo.ApplicationUserGroups", "GroupId", "dbo.Groups"); 135 | DropForeignKey("dbo.AspNetUserClaims", "User_Id", "dbo.IdentityUsers"); 136 | DropForeignKey("dbo.AspNetUserRoles", "UserId", "dbo.IdentityUsers"); 137 | DropForeignKey("dbo.AspNetUserRoles", "RoleId", "dbo.IdentityRoles"); 138 | DropForeignKey("dbo.AspNetUserLogins", "UserId", "dbo.IdentityUsers"); 139 | DropForeignKey("dbo.ApplicationRoleGroups", "GroupId", "dbo.Groups"); 140 | DropForeignKey("dbo.ApplicationRoleGroups", "RoleId", "dbo.AspNetRoles"); 141 | DropIndex("dbo.AspNetUsers", new[] { "Id" }); 142 | DropIndex("dbo.AspNetRoles", new[] { "Id" }); 143 | DropIndex("dbo.ApplicationUserGroups", new[] { "UserId" }); 144 | DropIndex("dbo.ApplicationUserGroups", new[] { "GroupId" }); 145 | DropIndex("dbo.AspNetUserClaims", new[] { "User_Id" }); 146 | DropIndex("dbo.AspNetUserRoles", new[] { "UserId" }); 147 | DropIndex("dbo.AspNetUserRoles", new[] { "RoleId" }); 148 | DropIndex("dbo.AspNetUserLogins", new[] { "UserId" }); 149 | DropIndex("dbo.ApplicationRoleGroups", new[] { "GroupId" }); 150 | DropIndex("dbo.ApplicationRoleGroups", new[] { "RoleId" }); 151 | DropTable("dbo.AspNetUsers"); 152 | DropTable("dbo.AspNetRoles"); 153 | DropTable("dbo.ApplicationUserGroups"); 154 | DropTable("dbo.AspNetUserRoles"); 155 | DropTable("dbo.AspNetUserLogins"); 156 | DropTable("dbo.AspNetUserClaims"); 157 | DropTable("dbo.IdentityUsers"); 158 | DropTable("dbo.IdentityRoles"); 159 | DropTable("dbo.ApplicationRoleGroups"); 160 | DropTable("dbo.Groups"); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Migrations/201402092222180_init.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | H4sIAAAAAAAEAO1dS2/kNhK+L7D/QdApWSDdtnPJDtoJHHucHezYHridXBu0RLeF1aNXYjv2/rU97E/KXwipJ8WXSIl6ONnLoC1RVWTVxyKryKr57b//2/zwGoXOC0yzIInP3dPVievA2Ev8IN6fu0f09M137g/f//Uvm49+9Or8UrX7lrTDX8bZufuM0OHDep15zzAC2SoKvDTJkie08pJoDfxkfXZy8vf16ekaYhIupuU4m/tjjIII5n/gPy+T2IMHdAThTeLDMCuf4zfbnKpzCyKYHYAHz92L7HAL0X0SwstjhpIo+A9AuE+r4kvXuQgDgHu1heGT64A4TlD+/sPPGdyiNIn32wN+AMKHtwPE7Z5AmMFyLB+a5rrDOjkjw1o3H/YSi1sPGA/5IxYNeiPdy4d97v6UJscD3QQ3+id8az3Aj76kyQGm6O0ePpUffvJdZ93+bs1+WH9GfUN4418x+vbMdW6PYQgeQ1iLipLpFiUp/AnGMAUI+l8AQjCNCQ2Yj4HjzvAi/1bcsG4w5FznBrx+hvEePZ+7+KfrXAev0K+elD34OQ4wQvFHKD1CQQ8ZrrfgJdjnHWb4ExBhxNzDMH+bPQeHAjirXOS78v11mkTkZ6mJ4vFumxxTj3Q/4d89gHQPUbsjm3WjWKW6Lw6HMPDyHhFqvbVPPuYRIGya8+iDloqHVIenZ99Z0SHDt+6wGqq6QChk3BMIlbJFQKhAYoJIYT9EoNgVrZteSRtxYJW3tAld1/kRZLDEBhlFZRjyl0oFX8HMS4NDYVEHW4heg1F0dgLrO91csmSFhwIGr8+pFDD5S+UoroM0QxMtKAzrz2Auzh8jEIRzrqC54RAvoYxqd1VTobmiWqhsFd1skKGicXUZgiD6I26v8oERZpZnt4TTLyA8jsBKir3CYAiQxyl3VzRtkCduwSFP0swa8v7IqwoZ3wgrC8/oC8iyX5PU/wfInkdntoXeMcXa2yIQHSbEeo4+sZ3tjXZ239oxKXS7+jnZB3F3V/Nmyq42LZRdpZr12W139zTfFqs6WjdQ9rNpJepmL/uRD72PESEfa7qGOQ/8+CXwiQQ0vqga456Ym6qqZ1ObK2aYU7NvyWx05sOWVKOZq1pSBRN88JTo66wZzAhxXGW50J4sRmMe1eDsIxvREDZQgqppJcLUYPAbLAadvRyOfMY16h0qNEB/71DhXPCfLFQoUsaubC51eqlWXY4v3dQatnt76exWp8OZ14H3RZYlXpCTUITCdwIT/zH2He0QaBNdEkbanZtjiALyAnfx3P0bJ2QdZrV0pMxYPqcuO/fu4isYQgSdC684kboEmQd8HqtYnH77CZ6uMCXWBoSXWN0oBUGM+LkdxF5wAKHuaBgCmu4p6WDNin1zBQ8wJnZRV306fZAefKxrdowAu+S1WVPYVEOWPjCQ4UZ4jNQgRYhDq/gQd6UbtJozpBf8BEKZAHCC8etwlayCE2FMshuX6bhray4OtxfOpYE17PLdJVH9xdlB9TgmwKRaXzodkO7npkZns6nXQY1ghy8GjWgB1YUm7yDIDigXjUxuGBMDk9PV4ldmsRunDRkdmzkYl+/fYnLDmAOX79ZeUgF8HcyIzq7EoCkOOXtCU3RoMDU2DQSqcMQ1PDmpVy7cFTdhl35+o8yxn9QdGOouSgYxrb8o0dvyd/OSEIwmeLhbE1KYTuRRdsWLhk4jG2BlhDY9UBmpLGyNKsJz+BuEv4Apj9OrR/ISviIOpeTDLUTM9aAm3te2aZyFbH8uij6IqImjFB3Ey8NfjljbBeggwq2SKorUOmxAtouiEbHqcF5JsfT8Dch2ybLZG+trvDYJHRqnTAdDnEK3GlPlsRPVvvPWLTsJTSLQ9aClCOfmuEnMmSJf6oW13m3BaAitdQuaF5M05tkZ9aT6qjF2UbDSVJg9Ri87/OYFoROYMwnNUYMTzWKFqDqCcRLCtqVFnemqhSWJExlEiiQjEs4Ag9jQCJNJcpysISADMPEhC3sCmgNJ9M02taRkLrSJEy0ZVLXCawpL4DaPKC3V8bNyZVP6yKZestgc02u53tom84s7F4zhkqvPwDulJnTVTJw1XTiYOFimGlAIrDqorz2B+t1mXSRmlg82a0kG5+YGHA5BvKcyOssnzrZI57z8ZmueMhkVNNZeS/as31JzQkkK9pB5i1njnuZpI1cAgUdAboFc+hHXzMTvqVi23B9eldVutmpOfpdYVGa3roQztBHqNR5nRJzOPHOAnSv8dw5JsAUhSAUXxi+T8BjFcudX/nVx7Zv+vnjCU9ismY5zvi0nKy4Q0Za8ll7EG0WLaupO4dTSmh4ZmRqqwxZaEbIDGDmVOjZGk5EGzGZTqcz5sKXCPtqrGXAdk4t72MxrZU3SZFov7CutQ9SfMvL77umrDpnToZeve0hcnrE5nsgXb+zaG4txZohot609Q4QdG0tdVJooTYR6rE+ryfukSTVP9SmVeZw0mfLR4ucq0d6QuSqGzjjKJ7x4hTVP9Sm1k85oau03+hSZzDKaJPNqkZaldI0tmpeOFF1jkElojIM0KvWWJkI9NqRVJtdyxMrni8REGaYcCROC5DdjTEhoqOwHiwvZsZycCpNq1lo71Ml2cpqt/LGWOZIn4y0EJdZ37up0MGOMmG0m7UDEzHWb34umokvjbTAteNEKMuMqdGledDvk17Gsl2H3/it3ScB4dSZBT25ZVsXXeTlqre05CfHdCqoHvTsnvWXSe+Mh7xcbzeW1zwV12SY19urgLhPE3ZQB1e5afVyEtWjiOtWyhDe3bxmC0Yo0WG3/HV6GAZZh0+AGxMETzNBD8i8Yn7tnJ6dnTIm/HuX21lnmh4usuReQsXeWfRlQ4Cl+Aan3DNKvIvD6dQelP0HFukocfCLqsCzTXI92hDtvGTJrAtICoYVqbYK70+9JTE0wwlhUPDFRaZxBBIXlb8bW5kz1uUYxxVxJrkHq4MtuDSJXb4MGYfr/lWzaPbNsIISFaqxRF9ShmRIGfdc4AxSI9xizqdPKduRPUC/kHWzUpOe972oDIii8O8YCLz36e1fC4orOmrhXAtsObFJrFYe14fdZqc9CTZJWLhD9nM1TMqvAMlcBC+V9j2lKpSw/CVu7PMpsFVGWBCl9pc4FpndbCGWe9HpFgsbQQiyDM/dnKW2ytNRHW+VMiqSXOSqLyBM3BpatGAQwyUHs6KUglr8i9i9LsiQTNje+5jBg2vhajP0yLC+yJICVidPDypu8O4jJLr6JMSY5w56+hoVOyZXF7PKpBPJ5ilPMsctXXahZ2i7ftEAKFVriQwzl814hhtmRorwwvyC8zLrgMb7sjqiqobkjlY139LZ095Ds5LHbwVt7BbLMY2EnqxVP8V1szO1Ex2awNir4FA0q+Iii2YM3Vl3wMbJz9uEz1abIjuWbqFISn1jM6rC8A9m6bCatklRcmjt3/ccEK7oI20tyuVnK4lglx0jcTMRXr8YK2422heTYt1+L2NIt9NkVM0rKrryVqmAnrs2gYlc6IkqeZRuheGuYi2tNdBd30qvtpOYtri/TWQFKqwCUmrOefsU7LhWqqWYdqFYUSuC6Qa/TPHf6rXzUmiOmbbqEVflWLWCe1UxVsnjZcUnTmkUwOMMmz50fXivEXiUsvpbJIgc8UfEraS0UpVCk1k+S6WVXHM1pgMXqVrQh5ZPadYUhpdK8tC8KHWBIItwj4mJqUYxYqWq4MFrbE0kSznBxTFCKaqAJ5bYN8kwx6+KwWl+K3xdwlRUWLpJeMZruXciwsI9l09xjt2MBZ6aRCw1ADgqGWLZrPbBvp9YZn/62Wd8f8ddRcV1ucwWzYN+Q2GCaMfRasYO6zaf4KanCF0yPqibMvb4biIAPELhIUfAEPIRfezDL8v9OL08GIFf/HqH/Kb47osMR4SHD6DFsXWEnoRAV/7ygW7vPm7v8UmhmYwi4mwEeAryLfzwGoV/3+1pwGVFCgsRYysQMoktEEjT2bzWl2yTWJFSKrw4NPcDoEGJi2V28BS9Q3rduGbYltrkKwD4FUVbSaL7Hf2L4+dHr978DHUjGEJKJAAA= 122 | 123 | 124 | dbo 125 | 126 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Migrations/Configuration.cs: -------------------------------------------------------------------------------- 1 | using AspNetRoleCustomization.Models; 2 | using System.Data.Entity.Migrations; 3 | 4 | namespace AspNetRoleCustomization.Migrations 5 | { 6 | using System; 7 | using System.Data.Entity; 8 | using System.Data.Entity.Migrations; 9 | using System.Linq; 10 | 11 | internal sealed class Configuration : DbMigrationsConfiguration 12 | { 13 | public Configuration() 14 | { 15 | AutomaticMigrationsEnabled = true; 16 | } 17 | 18 | 19 | protected override void Seed(ApplicationDbContext context) 20 | { 21 | this.AddUserAndRoles(); 22 | this.AddGroups(); 23 | } 24 | 25 | 26 | bool AddUserAndRoles() 27 | { 28 | bool success = false; 29 | 30 | var idManager = new IdentityManager(); 31 | success = idManager.CreateRole("Admin"); 32 | if (!success == true) return success; 33 | 34 | success = idManager.CreateRole("CanEdit"); 35 | if (!success == true) return success; 36 | 37 | success = idManager.CreateRole("User"); 38 | if (!success) return success; 39 | 40 | 41 | var newUser = new ApplicationUser() 42 | { 43 | UserName = "jatten", 44 | FirstName = "John", 45 | LastName = "Atten", 46 | Email = "jatten@typecastexception.com" 47 | }; 48 | 49 | // Be careful here - you will need to use a password which will 50 | // be valid under the password rules for the application, 51 | // or the process will abort: 52 | success = idManager.CreateUser(newUser, "Password1"); 53 | if (!success) return success; 54 | 55 | success = idManager.AddUserToRole(newUser.Id, "Admin"); 56 | if (!success) return success; 57 | 58 | success = idManager.AddUserToRole(newUser.Id, "CanEdit"); 59 | if (!success) return success; 60 | 61 | success = idManager.AddUserToRole(newUser.Id, "User"); 62 | if (!success) return success; 63 | 64 | return success; 65 | } 66 | 67 | public void AddGroups() 68 | { 69 | var idManager = new IdentityManager(); 70 | idManager.CreateGroup("Admins"); 71 | idManager.CreateGroup("Restricted Users"); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Models/AccountViewModels.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | // New namespace imports: 4 | using Microsoft.AspNet.Identity.EntityFramework; 5 | using System.Collections.Generic; 6 | 7 | namespace AspNetRoleCustomization.Models 8 | { 9 | public class ManageUserViewModel 10 | { 11 | [Required] 12 | [DataType(DataType.Password)] 13 | [Display(Name = "Current password")] 14 | public string OldPassword { get; set; } 15 | 16 | [Required] 17 | [StringLength(100, ErrorMessage = 18 | "The {0} must be at least {2} characters long.", MinimumLength = 6)] 19 | [DataType(DataType.Password)] 20 | [Display(Name = "New password")] 21 | public string NewPassword { get; set; } 22 | 23 | [DataType(DataType.Password)] 24 | [Display(Name = "Confirm new password")] 25 | [Compare("NewPassword", ErrorMessage = 26 | "The new password and confirmation password do not match.")] 27 | public string ConfirmPassword { get; set; } 28 | } 29 | 30 | 31 | public class LoginViewModel 32 | { 33 | [Required] 34 | [Display(Name = "User name")] 35 | public string UserName { get; set; } 36 | 37 | [Required] 38 | [DataType(DataType.Password)] 39 | [Display(Name = "Password")] 40 | public string Password { get; set; } 41 | 42 | [Display(Name = "Remember me?")] 43 | public bool RememberMe { get; set; } 44 | } 45 | 46 | 47 | public class RegisterViewModel 48 | { 49 | [Required] 50 | [Display(Name = "User name")] 51 | public string UserName { get; set; } 52 | 53 | [Required] 54 | [StringLength(100, ErrorMessage = 55 | "The {0} must be at least {2} characters long.", MinimumLength = 6)] 56 | [DataType(DataType.Password)] 57 | [Display(Name = "Password")] 58 | public string Password { get; set; } 59 | 60 | [DataType(DataType.Password)] 61 | [Display(Name = "Confirm password")] 62 | [Compare("Password", ErrorMessage = 63 | "The password and confirmation password do not match.")] 64 | public string ConfirmPassword { get; set; } 65 | 66 | // New Fields added to extend Application User class: 67 | 68 | [Required] 69 | [Display(Name = "First Name")] 70 | public string FirstName { get; set; } 71 | 72 | [Required] 73 | [Display(Name = "Last Name")] 74 | public string LastName { get; set; } 75 | 76 | [Required] 77 | public string Email { get; set; } 78 | 79 | // Return a pre-poulated instance of AppliationUser: 80 | public ApplicationUser GetUser() 81 | { 82 | var user = new ApplicationUser() 83 | { 84 | UserName = this.UserName, 85 | FirstName = this.FirstName, 86 | LastName = this.LastName, 87 | Email = this.Email, 88 | }; 89 | return user; 90 | } 91 | } 92 | 93 | 94 | public class EditUserViewModel 95 | { 96 | public EditUserViewModel() { } 97 | 98 | // Allow Initialization with an instance of ApplicationUser: 99 | public EditUserViewModel(ApplicationUser user) 100 | { 101 | this.UserName = user.UserName; 102 | this.FirstName = user.FirstName; 103 | this.LastName = user.LastName; 104 | this.Email = user.Email; 105 | } 106 | 107 | [Required] 108 | [Display(Name = "User Name")] 109 | public string UserName { get; set; } 110 | 111 | [Required] 112 | [Display(Name = "First Name")] 113 | public string FirstName { get; set; } 114 | 115 | [Required] 116 | [Display(Name = "Last Name")] 117 | public string LastName { get; set; } 118 | 119 | [Required] 120 | public string Email { get; set; } 121 | } 122 | 123 | 124 | public class UserPermissionsViewModel 125 | { 126 | public UserPermissionsViewModel() 127 | { 128 | this.Roles = new List(); 129 | } 130 | 131 | 132 | // Enable initialization with an instance of ApplicationUser: 133 | public UserPermissionsViewModel(ApplicationUser user) 134 | : this() 135 | { 136 | this.UserName = user.UserName; 137 | this.FirstName = user.FirstName; 138 | this.LastName = user.LastName; 139 | foreach(var role in user.Roles) 140 | { 141 | var appRole = (ApplicationRole)role.Role; 142 | var pvm = new PermissionsViewModel(appRole); 143 | this.Roles.Add(pvm); 144 | } 145 | } 146 | 147 | public string UserName { get; set; } 148 | public string FirstName { get; set; } 149 | public string LastName { get; set; } 150 | public List Roles { get; set; } 151 | } 152 | 153 | // Used to display a single role with a checkbox, within a list structure: 154 | public class PermissionsViewModel 155 | { 156 | public PermissionsViewModel() { } 157 | public PermissionsViewModel(ApplicationRole role) 158 | { 159 | this.RoleName = role.Name; 160 | this.Description = role.Description; 161 | } 162 | 163 | public string RoleName { get; set; } 164 | public string Description { get; set; } 165 | } 166 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Models/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Data.Entity.Infrastructure; 5 | using System.Data.Entity.ModelConfiguration; 6 | using System.Data.Entity.ModelConfiguration.Configuration; 7 | using System.Data.Entity.Validation; 8 | using System.Globalization; 9 | using System.Linq; 10 | using System.Linq.Expressions; 11 | using System.Reflection; 12 | using System.Runtime.CompilerServices; 13 | using Microsoft.AspNet.Identity.EntityFramework; 14 | 15 | namespace AspNetRoleCustomization.Models 16 | { 17 | public class ApplicationDbContext : IdentityDbContext 18 | { 19 | public ApplicationDbContext() 20 | : base("DefaultConnection") 21 | { 22 | 23 | } 24 | 25 | 26 | protected override void OnModelCreating(DbModelBuilder modelBuilder) 27 | { 28 | if (modelBuilder == null) 29 | { 30 | throw new ArgumentNullException("modelBuilder"); 31 | } 32 | modelBuilder.Entity().ToTable("AspNetUsers"); 33 | EntityTypeConfiguration table = modelBuilder.Entity().ToTable("AspNetUsers"); 34 | table.Property((ApplicationUser u) => u.UserName).IsRequired(); 35 | 36 | modelBuilder.Entity().HasMany((ApplicationUser u) => u.Roles); 37 | modelBuilder.Entity().HasKey((IdentityUserRole r) => new { UserId = r.UserId, RoleId = r.RoleId }).ToTable("AspNetUserRoles"); 38 | 39 | modelBuilder.Entity().HasMany((ApplicationUser u) => u.Groups); 40 | modelBuilder.Entity().HasKey((ApplicationUserGroup r) => new { UserId = r.UserId, GroupId = r.GroupId }).ToTable("ApplicationUserGroups"); 41 | 42 | modelBuilder.Entity().HasMany((Group g) => g.Roles); 43 | modelBuilder.Entity().HasKey((ApplicationRoleGroup gr) => new { RoleId = gr.RoleId, GroupId = gr.GroupId }).ToTable("ApplicationRoleGroups"); 44 | 45 | EntityTypeConfiguration groupsConfig = modelBuilder.Entity().ToTable("Groups"); 46 | groupsConfig.Property((Group r) => r.Name).IsRequired(); 47 | 48 | EntityTypeConfiguration entityTypeConfiguration = modelBuilder.Entity().HasKey((IdentityUserLogin l) => new { UserId = l.UserId, LoginProvider = l.LoginProvider, ProviderKey = l.ProviderKey }).ToTable("AspNetUserLogins"); 49 | entityTypeConfiguration.HasRequired((IdentityUserLogin u) => u.User); 50 | EntityTypeConfiguration table1 = modelBuilder.Entity().ToTable("AspNetUserClaims"); 51 | table1.HasRequired((IdentityUserClaim u) => u.User); 52 | EntityTypeConfiguration entityTypeConfiguration1 = modelBuilder.Entity().ToTable("AspNetRoles"); 53 | entityTypeConfiguration1.Property((ApplicationRole r) => r.Name).IsRequired(); 54 | } 55 | 56 | public virtual System.Data.Entity.DbSet Groups { get; set; } 57 | 58 | public System.Data.Entity.DbSet ApplicationRoles { get; set; } 59 | //new public virtual IDbSet Roles { get; set; } 60 | 61 | } 62 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Models/ApplicationRole.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | 6 | namespace AspNetRoleCustomization.Models 7 | { 8 | public class ApplicationRole : IdentityRole 9 | { 10 | public string Description { get; set; } 11 | 12 | public ApplicationRole() : base() 13 | { 14 | } 15 | 16 | 17 | public ApplicationRole(string roleName) : base(roleName) 18 | { 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Models/ApplicationRoleGroup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | 6 | 7 | namespace AspNetRoleCustomization.Models 8 | { 9 | public class ApplicationRoleGroup 10 | { 11 | 12 | public string RoleId { get; set; } 13 | public int GroupId { get; set; } 14 | 15 | public virtual ApplicationRole Role { get; set; } 16 | public virtual Group Group { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Models/ApplicationUser.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | 6 | namespace AspNetRoleCustomization.Models 7 | { 8 | public class ApplicationUser : IdentityUser 9 | { 10 | public ApplicationUser() : base() 11 | { 12 | this.Groups = new HashSet(); 13 | } 14 | 15 | 16 | [Required] 17 | public string FirstName { get; set; } 18 | 19 | [Required] 20 | public string LastName { get; set; } 21 | 22 | [Required] 23 | public string Email { get; set; } 24 | 25 | 26 | public virtual ICollection Groups { get; set; } 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Models/ApplicationUserGroup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | 6 | namespace AspNetRoleCustomization.Models 7 | { 8 | public class ApplicationUserGroup 9 | { 10 | [Required] 11 | public string UserId { get; set; } 12 | [Required] 13 | public int GroupId { get; set; } 14 | 15 | public virtual ApplicationUser User { get; set; } 16 | public virtual Group Group { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Models/Group.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | 6 | namespace AspNetRoleCustomization.Models 7 | { 8 | public class Group 9 | { 10 | public Group() 11 | { 12 | this.Roles = new HashSet(); 13 | } 14 | 15 | 16 | public Group(string name) : this() 17 | { 18 | this.Name = name; 19 | } 20 | 21 | 22 | [Key] 23 | [Required] 24 | public int Id { get; set; } 25 | 26 | public string Name { get; set; } 27 | public virtual HashSet Roles { get; set; } 28 | } 29 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Models/IdentityManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity.EntityFramework; 2 | using Microsoft.AspNet.Identity; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Collections.Generic; 5 | using System.Data.Entity; 6 | using System.Linq; 7 | using System; 8 | 9 | namespace AspNetRoleCustomization.Models 10 | { 11 | public class IdentityManager 12 | { 13 | private ApplicationDbContext _db = new ApplicationDbContext(); 14 | 15 | private UserManager _userManager = new UserManager( 16 | new UserStore(new ApplicationDbContext())); 17 | 18 | private RoleManager _roleManager = new RoleManager( 19 | new RoleStore(new ApplicationDbContext())); 20 | 21 | public bool RoleExists(string name) 22 | { 23 | return _roleManager.RoleExists(name); 24 | } 25 | 26 | 27 | public bool CreateRole(string name) 28 | { 29 | var idResult = _roleManager.Create(new ApplicationRole(name)); 30 | return idResult.Succeeded; 31 | } 32 | 33 | 34 | public bool CreateUser(ApplicationUser user, string password) 35 | { 36 | var idResult = _userManager.Create(user, password); 37 | return idResult.Succeeded; 38 | } 39 | 40 | 41 | public bool AddUserToRole(string userId, string roleName) 42 | { 43 | var idResult = _userManager.AddToRole(userId, roleName); 44 | return idResult.Succeeded; 45 | } 46 | 47 | 48 | public void ClearUserRoles(string userId) 49 | { 50 | var user = _userManager.FindById(userId); 51 | var userRoles = user.Roles.ToList(); 52 | foreach (var role in userRoles) 53 | { 54 | _userManager.RemoveFromRole(userId, role.Role.Name); 55 | } 56 | } 57 | 58 | 59 | public void RemoveFromRole(string userId, string roleName) 60 | { 61 | _userManager.RemoveFromRole(userId, roleName); 62 | } 63 | 64 | 65 | public void DeleteRole(string roleId) 66 | { 67 | var roleGroups = _db.Groups.Where(g => g.Roles.Any(r => r.RoleId == roleId)); 68 | var roleUsers = _db.Users.Where(u => u.Roles.Any(r => r.RoleId == roleId)); 69 | var role = _db.ApplicationRoles.Find(roleId); 70 | 71 | foreach(var user in roleUsers) 72 | { 73 | this.RemoveFromRole(user.Id, role.Name); 74 | } 75 | 76 | foreach(var group in roleGroups) 77 | { 78 | var arg = new ApplicationRoleGroup() 79 | { 80 | RoleId = roleId, 81 | GroupId = group.Id, 82 | Role = role, 83 | Group = group 84 | }; 85 | 86 | group.Roles.Remove(arg); 87 | } 88 | _db.ApplicationRoles.Remove(role); 89 | _db.SaveChanges(); 90 | } 91 | 92 | 93 | public void CreateGroup(string groupName) 94 | { 95 | if(this.GroupNameExists(groupName)) 96 | { 97 | throw new Exception("A group by that name already exists in the database. Please choose another name."); 98 | } 99 | 100 | var newGroup = new Group(groupName); 101 | _db.Groups.Add(newGroup); 102 | _db.SaveChanges(); 103 | } 104 | 105 | 106 | public bool GroupNameExists(string groupName) 107 | { 108 | var g = _db.Groups.Where(gr => gr.Name == groupName); 109 | if(g.Count() > 0) 110 | { 111 | return true; 112 | } 113 | return false; 114 | } 115 | 116 | 117 | public void ClearUserGroups(string userId) 118 | { 119 | this.ClearUserRoles(userId); 120 | var user = _db.Users.Find(userId); 121 | user.Groups.Clear(); 122 | _db.SaveChanges(); 123 | } 124 | 125 | 126 | public void AddUserToGroup(string userId, int roleGroupId) 127 | { 128 | var group = _db.Groups.Find(roleGroupId); 129 | var user = _db.Users.Find(userId); 130 | 131 | var userGroup = new ApplicationUserGroup() 132 | { 133 | Group = group, 134 | GroupId = group.Id, 135 | User = user, 136 | UserId = user.Id 137 | }; 138 | 139 | foreach(var role in group.Roles) 140 | { 141 | _userManager.AddToRole(userId, role.Role.Name); 142 | } 143 | user.Groups.Add(userGroup); 144 | _db.SaveChanges(); 145 | } 146 | 147 | 148 | public void ClearGroupRoles(int groupId) 149 | { 150 | var group = _db.Groups.Find(groupId); 151 | var rolesToRemove = group.Roles.ToList(); 152 | var groupUsers = _db.Users.Where(u => u.Groups.Any(g => g.GroupId == group.Id)); 153 | foreach(var user in groupUsers) 154 | { 155 | foreach(var role in group.Roles) 156 | { 157 | this.RemoveFromRole(user.Id, role.Role.Name); 158 | } 159 | } 160 | group.Roles.Clear(); 161 | _db.SaveChanges(); 162 | } 163 | 164 | 165 | public void AddRoleToGroup(int groupId, string roleName) 166 | { 167 | var group = _db.Groups.Find(groupId); 168 | var role = _db.Roles.First(r => r.Name == roleName); 169 | var newgroupRole = new ApplicationRoleGroup() 170 | { 171 | GroupId = group.Id, 172 | Group = group, 173 | RoleId = role.Id, 174 | Role = (ApplicationRole)role 175 | }; 176 | group.Roles.Add(newgroupRole); 177 | _db.SaveChanges(); 178 | 179 | // Add all of the users in this group to the new role: 180 | var groupUsers = _db.Users.Where(u => u.Groups.Any(g => g.GroupId == group.Id)); 181 | foreach(var user in groupUsers) 182 | { 183 | this.AddUserToRole(user.Id, role.Name); 184 | } 185 | } 186 | 187 | 188 | 189 | //public void ClearUserRoleGroups(string userId) 190 | //{ 191 | // var groups = _db.RoleGroups.Where(g => g.Users.Any(u => u.Id == userId)); 192 | // foreach(var group in groups) 193 | // { 194 | // this.RemoveUserFromRoleGroup(userId, group); 195 | // } 196 | //} 197 | 198 | 199 | //public void RemoveUserFromRoleGroup(string userId, Group group) 200 | //{ 201 | // var user = _userManager.FindById(userId); 202 | // foreach(var role in group.Roles) 203 | // { 204 | // _userManager.RemoveFromRole(user.Id, role.Name); 205 | // } 206 | // var newGroup = _db.RoleGroups.Find(group.Id); 207 | // var newUser = _db.Users.Find(userId); 208 | // group.Users.Remove(newUser); 209 | // _db.SaveChanges(); 210 | //} 211 | 212 | 213 | //public void AddUserToRoleGroup(string userId, int roleGroupId) 214 | //{ 215 | // var group = _db.RoleGroups.Find(roleGroupId); 216 | // var user = _db.Users.Find(userId); 217 | // group.Users.Add(user); 218 | // _db.SaveChanges(); 219 | 220 | // foreach(var role in group.Roles) 221 | // { 222 | // this.AddUserToRole(user.Id, role.Name); 223 | // } 224 | //} 225 | 226 | 227 | } 228 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Models/RoleManagementViewModels.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Web; 4 | using AspNetRoleCustomization.Models; 5 | using System.ComponentModel.DataAnnotations; 6 | 7 | // New namespace imports: 8 | using Microsoft.AspNet.Identity.EntityFramework; 9 | using System.Collections.Generic; 10 | 11 | namespace AspNetRoleCustomization.Models 12 | { 13 | // Wrapper for SelectGroupEditorViewModel to select user group membership: 14 | public class SelectUserGroupsViewModel 15 | { 16 | public string UserName { get; set; } 17 | public string FirstName { get; set; } 18 | public string LastName { get; set; } 19 | public List Groups { get; set; } 20 | 21 | public SelectUserGroupsViewModel() 22 | { 23 | this.Groups = new List(); 24 | } 25 | 26 | public SelectUserGroupsViewModel(ApplicationUser user) 27 | : this() 28 | { 29 | this.UserName = user.UserName; 30 | this.FirstName = user.FirstName; 31 | this.LastName = user.LastName; 32 | 33 | var Db = new ApplicationDbContext(); 34 | 35 | // Add all available groups to the public list: 36 | var allGroups = Db.Groups; 37 | foreach (var role in allGroups) 38 | { 39 | // An EditorViewModel will be used by Editor Template: 40 | var rvm = new SelectGroupEditorViewModel(role); 41 | this.Groups.Add(rvm); 42 | } 43 | 44 | // Set the Selected property to true where user is already a member: 45 | foreach (var group in user.Groups) 46 | { 47 | var checkUserRole = 48 | this.Groups.Find(r => r.GroupName == group.Group.Name); 49 | checkUserRole.Selected = true; 50 | } 51 | } 52 | } 53 | 54 | 55 | // Used to display a single role group with a checkbox, within a list structure: 56 | public class SelectGroupEditorViewModel 57 | { 58 | public SelectGroupEditorViewModel() { } 59 | public SelectGroupEditorViewModel(Group group) 60 | { 61 | this.GroupName = group.Name; 62 | this.GroupId = group.Id; 63 | } 64 | 65 | public bool Selected { get; set; } 66 | 67 | [Required] 68 | public int GroupId { get; set; } 69 | 70 | [Required] 71 | public string GroupName { get; set; } 72 | } 73 | 74 | 75 | public class SelectGroupRolesViewModel 76 | { 77 | public SelectGroupRolesViewModel() 78 | { 79 | this.Roles = new List(); 80 | } 81 | 82 | 83 | // Enable initialization with an instance of ApplicationUser: 84 | public SelectGroupRolesViewModel(Group group) 85 | : this() 86 | { 87 | this.GroupId = group.Id; 88 | this.GroupName = group.Name; 89 | 90 | var Db = new ApplicationDbContext(); 91 | 92 | // Add all available roles to the list of EditorViewModels: 93 | var allRoles = Db.Roles; 94 | foreach (var role in allRoles) 95 | { 96 | // An EditorViewModel will be used by Editor Template: 97 | var rvm = new SelectRoleEditorViewModel(role); 98 | this.Roles.Add(rvm); 99 | } 100 | 101 | // Set the Selected property to true for those roles for 102 | // which the current user is a member: 103 | foreach (var groupRole in group.Roles) 104 | { 105 | var checkGroupRole = 106 | this.Roles.Find(r => r.RoleName == groupRole.Role.Name); 107 | checkGroupRole.Selected = true; 108 | } 109 | } 110 | 111 | public int GroupId { get; set; } 112 | public string GroupName { get; set; } 113 | public List Roles { get; set; } 114 | } 115 | 116 | 117 | // Used to display a single role with a checkbox, within a list structure: 118 | public class SelectRoleEditorViewModel 119 | { 120 | public SelectRoleEditorViewModel() { } 121 | public SelectRoleEditorViewModel(IdentityRole role) 122 | { 123 | this.RoleName = role.Name; 124 | } 125 | 126 | public bool Selected { get; set; } 127 | 128 | [Required] 129 | public string RoleName { get; set; } 130 | } 131 | 132 | 133 | //public class SelectGroupRolesViewModel 134 | //{ 135 | // public SelectGroupRolesViewModel() 136 | // { 137 | // this.Roles = new List(); 138 | // } 139 | 140 | 141 | 142 | // public SelectGroupRolesViewModel(Group group) 143 | // : this() 144 | // { 145 | // this.GroupId = group.Id; 146 | // this.GroupName = group.Name; 147 | 148 | // var Db = new ApplicationDbContext(); 149 | 150 | // Add all available roles to the list of EditorViewModels: 151 | // var allRoles = Db.Roles; 152 | // foreach (var role in allRoles) 153 | // { 154 | // An EditorViewModel will be used by Editor Template: 155 | // var rvm = new SelectRoleEditorViewModel(role); 156 | // this.Roles.Add(rvm); 157 | // } 158 | 159 | // foreach (var roleGroup in group.Roles) 160 | // { 161 | // var checkGroupRole = 162 | // this.Roles.Find(r => r.RoleName == roleGroup.Role.Id); 163 | // checkGroupRole.Selected = true; 164 | // } 165 | // } 166 | 167 | // public int GroupId { get; set; } 168 | // public string GroupName { get; set; } 169 | // public List Roles { get; set; } 170 | // } 171 | //} 172 | 173 | 174 | 175 | 176 | //// Used to display a single role with a checkbox, within a list structure: 177 | //public class SelectRoleEditorViewModel 178 | //{ 179 | // public SelectRoleEditorViewModel() { } 180 | // public SelectRoleEditorViewModel(IdentityRole role) 181 | // { 182 | // this.RoleName = role.Name; 183 | // } 184 | 185 | // public bool Selected { get; set; } 186 | 187 | // [Required] 188 | // public string RoleName { get; set; } 189 | //} 190 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Project_Readme.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Your ASP.NET application 6 | 95 | 96 | 97 | 98 | 102 | 103 |
104 |
105 |

This application consists of:

106 |
    107 |
  • Sample pages showing basic nav between Home, About, and Contact
  • 108 |
  • Theming using Bootstrap
  • 109 |
  • Authentication, if selected, shows how to register and sign in
  • 110 |
  • ASP.NET features managed using NuGet
  • 111 |
112 |
113 | 114 | 131 | 132 |
133 |

Deploy

134 | 139 |
140 | 141 |
142 |

Get help

143 | 147 |
148 |
149 | 150 | 151 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/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("AspNetRoleCustomization")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AspNetRoleCustomization")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 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("007b4066-9928-4140-a3cb-4cc527b22a69")] 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 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Scripts/_references.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xivSolutions/AspNetAdvancedRoleManagement/032526e015a5fd03d2da6e8812624da59b624a08/AspNetRoleCustomization/Scripts/_references.js -------------------------------------------------------------------------------- /AspNetRoleCustomization/Scripts/jquery.validate.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 | /*! jQuery Validation Plugin - v1.11.1 - 3/22/2013\n* https://github.com/jzaefferer/jquery-validation 16 | * Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */(function(t){t.extend(t.fn,{validate:function(e){if(!this.length)return e&&e.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."),void 0;var i=t.data(this[0],"validator");return i?i:(this.attr("novalidate","novalidate"),i=new t.validator(e,this[0]),t.data(this[0],"validator",i),i.settings.onsubmit&&(this.validateDelegate(":submit","click",function(e){i.settings.submitHandler&&(i.submitButton=e.target),t(e.target).hasClass("cancel")&&(i.cancelSubmit=!0),void 0!==t(e.target).attr("formnovalidate")&&(i.cancelSubmit=!0)}),this.submit(function(e){function s(){var s;return i.settings.submitHandler?(i.submitButton&&(s=t("").attr("name",i.submitButton.name).val(t(i.submitButton).val()).appendTo(i.currentForm)),i.settings.submitHandler.call(i,i.currentForm,e),i.submitButton&&s.remove(),!1):!0}return i.settings.debug&&e.preventDefault(),i.cancelSubmit?(i.cancelSubmit=!1,s()):i.form()?i.pendingRequest?(i.formSubmitted=!0,!1):s():(i.focusInvalid(),!1)})),i)},valid:function(){if(t(this[0]).is("form"))return this.validate().form();var e=!0,i=t(this[0].form).validate();return this.each(function(){e=e&&i.element(this)}),e},removeAttrs:function(e){var i={},s=this;return t.each(e.split(/\s/),function(t,e){i[e]=s.attr(e),s.removeAttr(e)}),i},rules:function(e,i){var s=this[0];if(e){var r=t.data(s.form,"validator").settings,n=r.rules,a=t.validator.staticRules(s);switch(e){case"add":t.extend(a,t.validator.normalizeRule(i)),delete a.messages,n[s.name]=a,i.messages&&(r.messages[s.name]=t.extend(r.messages[s.name],i.messages));break;case"remove":if(!i)return delete n[s.name],a;var u={};return t.each(i.split(/\s/),function(t,e){u[e]=a[e],delete a[e]}),u}}var o=t.validator.normalizeRules(t.extend({},t.validator.classRules(s),t.validator.attributeRules(s),t.validator.dataRules(s),t.validator.staticRules(s)),s);if(o.required){var l=o.required;delete o.required,o=t.extend({required:l},o)}return o}}),t.extend(t.expr[":"],{blank:function(e){return!t.trim(""+t(e).val())},filled:function(e){return!!t.trim(""+t(e).val())},unchecked:function(e){return!t(e).prop("checked")}}),t.validator=function(e,i){this.settings=t.extend(!0,{},t.validator.defaults,e),this.currentForm=i,this.init()},t.validator.format=function(e,i){return 1===arguments.length?function(){var i=t.makeArray(arguments);return i.unshift(e),t.validator.format.apply(this,i)}:(arguments.length>2&&i.constructor!==Array&&(i=t.makeArray(arguments).slice(1)),i.constructor!==Array&&(i=[i]),t.each(i,function(t,i){e=e.replace(RegExp("\\{"+t+"\\}","g"),function(){return i})}),e)},t.extend(t.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusInvalid:!0,errorContainer:t([]),errorLabelContainer:t([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(t){this.lastActive=t,this.settings.focusCleanup&&!this.blockFocusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,t,this.settings.errorClass,this.settings.validClass),this.addWrapper(this.errorsFor(t)).hide())},onfocusout:function(t){this.checkable(t)||!(t.name in this.submitted)&&this.optional(t)||this.element(t)},onkeyup:function(t,e){(9!==e.which||""!==this.elementValue(t))&&(t.name in this.submitted||t===this.lastElement)&&this.element(t)},onclick:function(t){t.name in this.submitted?this.element(t):t.parentNode.name in this.submitted&&this.element(t.parentNode)},highlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).addClass(i).removeClass(s):t(e).addClass(i).removeClass(s)},unhighlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).removeClass(i).addClass(s):t(e).removeClass(i).addClass(s)}},setDefaults:function(e){t.extend(t.validator.defaults,e)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",maxlength:t.validator.format("Please enter no more than {0} characters."),minlength:t.validator.format("Please enter at least {0} characters."),rangelength:t.validator.format("Please enter a value between {0} and {1} characters long."),range:t.validator.format("Please enter a value between {0} and {1}."),max:t.validator.format("Please enter a value less than or equal to {0}."),min:t.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function e(e){var i=t.data(this[0].form,"validator"),s="on"+e.type.replace(/^validate/,"");i.settings[s]&&i.settings[s].call(i,this[0],e)}this.labelContainer=t(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||t(this.currentForm),this.containers=t(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var i=this.groups={};t.each(this.settings.groups,function(e,s){"string"==typeof s&&(s=s.split(/\s/)),t.each(s,function(t,s){i[s]=e})});var s=this.settings.rules;t.each(s,function(e,i){s[e]=t.validator.normalizeRule(i)}),t(this.currentForm).validateDelegate(":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'] ","focusin focusout keyup",e).validateDelegate("[type='radio'], [type='checkbox'], select, option","click",e),this.settings.invalidHandler&&t(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){return this.checkForm(),t.extend(this.submitted,this.errorMap),this.invalid=t.extend({},this.errorMap),this.valid()||t(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var t=0,e=this.currentElements=this.elements();e[t];t++)this.check(e[t]);return this.valid()},element:function(e){e=this.validationTargetFor(this.clean(e)),this.lastElement=e,this.prepareElement(e),this.currentElements=t(e);var i=this.check(e)!==!1;return i?delete this.invalid[e.name]:this.invalid[e.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),i},showErrors:function(e){if(e){t.extend(this.errorMap,e),this.errorList=[];for(var i in e)this.errorList.push({message:e[i],element:this.findByName(i)[0]});this.successList=t.grep(this.successList,function(t){return!(t.name in e)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){t.fn.resetForm&&t(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors(),this.elements().removeClass(this.settings.errorClass).removeData("previousValue")},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(t){var e=0;for(var i in t)e++;return e},hideErrors:function(){this.addWrapper(this.toHide).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{t(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(e){}},findLastActive:function(){var e=this.lastActive;return e&&1===t.grep(this.errorList,function(t){return t.element.name===e.name}).length&&e},elements:function(){var e=this,i={};return t(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){return!this.name&&e.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in i||!e.objectLength(t(this).rules())?!1:(i[this.name]=!0,!0)})},clean:function(e){return t(e)[0]},errors:function(){var e=this.settings.errorClass.replace(" ",".");return t(this.settings.errorElement+"."+e,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=t([]),this.toHide=t([]),this.currentElements=t([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(t){this.reset(),this.toHide=this.errorsFor(t)},elementValue:function(e){var i=t(e).attr("type"),s=t(e).val();return"radio"===i||"checkbox"===i?t("input[name='"+t(e).attr("name")+"']:checked").val():"string"==typeof s?s.replace(/\r/g,""):s},check:function(e){e=this.validationTargetFor(this.clean(e));var i,s=t(e).rules(),r=!1,n=this.elementValue(e);for(var a in s){var u={method:a,parameters:s[a]};try{if(i=t.validator.methods[a].call(this,n,e,u.parameters),"dependency-mismatch"===i){r=!0;continue}if(r=!1,"pending"===i)return this.toHide=this.toHide.not(this.errorsFor(e)),void 0;if(!i)return this.formatAndAdd(e,u),!1}catch(o){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+e.id+", check the '"+u.method+"' method.",o),o}}return r?void 0:(this.objectLength(s)&&this.successList.push(e),!0)},customDataMessage:function(e,i){return t(e).data("msg-"+i.toLowerCase())||e.attributes&&t(e).attr("data-msg-"+i.toLowerCase())},customMessage:function(t,e){var i=this.settings.messages[t];return i&&(i.constructor===String?i:i[e])},findDefined:function(){for(var t=0;arguments.length>t;t++)if(void 0!==arguments[t])return arguments[t];return void 0},defaultMessage:function(e,i){return this.findDefined(this.customMessage(e.name,i),this.customDataMessage(e,i),!this.settings.ignoreTitle&&e.title||void 0,t.validator.messages[i],"Warning: No message defined for "+e.name+"")},formatAndAdd:function(e,i){var s=this.defaultMessage(e,i.method),r=/\$?\{(\d+)\}/g;"function"==typeof s?s=s.call(this,i.parameters,e):r.test(s)&&(s=t.validator.format(s.replace(r,"{$1}"),i.parameters)),this.errorList.push({message:s,element:e}),this.errorMap[e.name]=s,this.submitted[e.name]=s},addWrapper:function(t){return this.settings.wrapper&&(t=t.add(t.parent(this.settings.wrapper))),t},defaultShowErrors:function(){var t,e;for(t=0;this.errorList[t];t++){var i=this.errorList[t];this.settings.highlight&&this.settings.highlight.call(this,i.element,this.settings.errorClass,this.settings.validClass),this.showLabel(i.element,i.message)}if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(t=0;this.successList[t];t++)this.showLabel(this.successList[t]);if(this.settings.unhighlight)for(t=0,e=this.validElements();e[t];t++)this.settings.unhighlight.call(this,e[t],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return t(this.errorList).map(function(){return this.element})},showLabel:function(e,i){var s=this.errorsFor(e);s.length?(s.removeClass(this.settings.validClass).addClass(this.settings.errorClass),s.html(i)):(s=t("<"+this.settings.errorElement+">").attr("for",this.idOrName(e)).addClass(this.settings.errorClass).html(i||""),this.settings.wrapper&&(s=s.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.append(s).length||(this.settings.errorPlacement?this.settings.errorPlacement(s,t(e)):s.insertAfter(e))),!i&&this.settings.success&&(s.text(""),"string"==typeof this.settings.success?s.addClass(this.settings.success):this.settings.success(s,e)),this.toShow=this.toShow.add(s)},errorsFor:function(e){var i=this.idOrName(e);return this.errors().filter(function(){return t(this).attr("for")===i})},idOrName:function(t){return this.groups[t.name]||(this.checkable(t)?t.name:t.id||t.name)},validationTargetFor:function(t){return this.checkable(t)&&(t=this.findByName(t.name).not(this.settings.ignore)[0]),t},checkable:function(t){return/radio|checkbox/i.test(t.type)},findByName:function(e){return t(this.currentForm).find("[name='"+e+"']")},getLength:function(e,i){switch(i.nodeName.toLowerCase()){case"select":return t("option:selected",i).length;case"input":if(this.checkable(i))return this.findByName(i.name).filter(":checked").length}return e.length},depend:function(t,e){return this.dependTypes[typeof t]?this.dependTypes[typeof t](t,e):!0},dependTypes:{"boolean":function(t){return t},string:function(e,i){return!!t(e,i.form).length},"function":function(t,e){return t(e)}},optional:function(e){var i=this.elementValue(e);return!t.validator.methods.required.call(this,i,e)&&"dependency-mismatch"},startRequest:function(t){this.pending[t.name]||(this.pendingRequest++,this.pending[t.name]=!0)},stopRequest:function(e,i){this.pendingRequest--,0>this.pendingRequest&&(this.pendingRequest=0),delete this.pending[e.name],i&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(t(this.currentForm).submit(),this.formSubmitted=!1):!i&&0===this.pendingRequest&&this.formSubmitted&&(t(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(e){return t.data(e,"previousValue")||t.data(e,"previousValue",{old:null,valid:!0,message:this.defaultMessage(e,"remote")})}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(e,i){e.constructor===String?this.classRuleSettings[e]=i:t.extend(this.classRuleSettings,e)},classRules:function(e){var i={},s=t(e).attr("class");return s&&t.each(s.split(" "),function(){this in t.validator.classRuleSettings&&t.extend(i,t.validator.classRuleSettings[this])}),i},attributeRules:function(e){var i={},s=t(e),r=s[0].getAttribute("type");for(var n in t.validator.methods){var a;"required"===n?(a=s.get(0).getAttribute(n),""===a&&(a=!0),a=!!a):a=s.attr(n),/min|max/.test(n)&&(null===r||/number|range|text/.test(r))&&(a=Number(a)),a?i[n]=a:r===n&&"range"!==r&&(i[n]=!0)}return i.maxlength&&/-1|2147483647|524288/.test(i.maxlength)&&delete i.maxlength,i},dataRules:function(e){var i,s,r={},n=t(e);for(i in t.validator.methods)s=n.data("rule-"+i.toLowerCase()),void 0!==s&&(r[i]=s);return r},staticRules:function(e){var i={},s=t.data(e.form,"validator");return s.settings.rules&&(i=t.validator.normalizeRule(s.settings.rules[e.name])||{}),i},normalizeRules:function(e,i){return t.each(e,function(s,r){if(r===!1)return delete e[s],void 0;if(r.param||r.depends){var n=!0;switch(typeof r.depends){case"string":n=!!t(r.depends,i.form).length;break;case"function":n=r.depends.call(i,i)}n?e[s]=void 0!==r.param?r.param:!0:delete e[s]}}),t.each(e,function(s,r){e[s]=t.isFunction(r)?r(i):r}),t.each(["minlength","maxlength"],function(){e[this]&&(e[this]=Number(e[this]))}),t.each(["rangelength","range"],function(){var i;e[this]&&(t.isArray(e[this])?e[this]=[Number(e[this][0]),Number(e[this][1])]:"string"==typeof e[this]&&(i=e[this].split(/[\s,]+/),e[this]=[Number(i[0]),Number(i[1])]))}),t.validator.autoCreateRanges&&(e.min&&e.max&&(e.range=[e.min,e.max],delete e.min,delete e.max),e.minlength&&e.maxlength&&(e.rangelength=[e.minlength,e.maxlength],delete e.minlength,delete e.maxlength)),e},normalizeRule:function(e){if("string"==typeof e){var i={};t.each(e.split(/\s/),function(){i[this]=!0}),e=i}return e},addMethod:function(e,i,s){t.validator.methods[e]=i,t.validator.messages[e]=void 0!==s?s:t.validator.messages[e],3>i.length&&t.validator.addClassRules(e,t.validator.normalizeRule(e))},methods:{required:function(e,i,s){if(!this.depend(s,i))return"dependency-mismatch";if("select"===i.nodeName.toLowerCase()){var r=t(i).val();return r&&r.length>0}return this.checkable(i)?this.getLength(e,i)>0:t.trim(e).length>0},email:function(t,e){return this.optional(e)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(t)},url:function(t,e){return this.optional(e)||/^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(t)},date:function(t,e){return this.optional(e)||!/Invalid|NaN/.test(""+new Date(t))},dateISO:function(t,e){return this.optional(e)||/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(t)},number:function(t,e){return this.optional(e)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(t)},digits:function(t,e){return this.optional(e)||/^\d+$/.test(t)},creditcard:function(t,e){if(this.optional(e))return"dependency-mismatch";if(/[^0-9 \-]+/.test(t))return!1;var i=0,s=0,r=!1;t=t.replace(/\D/g,"");for(var n=t.length-1;n>=0;n--){var a=t.charAt(n);s=parseInt(a,10),r&&(s*=2)>9&&(s-=9),i+=s,r=!r}return 0===i%10},minlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s},maxlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||s>=r},rangelength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s[0]&&s[1]>=r},min:function(t,e,i){return this.optional(e)||t>=i},max:function(t,e,i){return this.optional(e)||i>=t},range:function(t,e,i){return this.optional(e)||t>=i[0]&&i[1]>=t},equalTo:function(e,i,s){var r=t(s);return this.settings.onfocusout&&r.unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){t(i).valid()}),e===r.val()},remote:function(e,i,s){if(this.optional(i))return"dependency-mismatch";var r=this.previousValue(i);if(this.settings.messages[i.name]||(this.settings.messages[i.name]={}),r.originalMessage=this.settings.messages[i.name].remote,this.settings.messages[i.name].remote=r.message,s="string"==typeof s&&{url:s}||s,r.old===e)return r.valid;r.old=e;var n=this;this.startRequest(i);var a={};return a[i.name]=e,t.ajax(t.extend(!0,{url:s,mode:"abort",port:"validate"+i.name,dataType:"json",data:a,success:function(s){n.settings.messages[i.name].remote=r.originalMessage;var a=s===!0||"true"===s;if(a){var u=n.formSubmitted;n.prepareElement(i),n.formSubmitted=u,n.successList.push(i),delete n.invalid[i.name],n.showErrors()}else{var o={},l=s||n.defaultMessage(i,"remote");o[i.name]=r.message=t.isFunction(l)?l(e):l,n.invalid[i.name]=!0,n.showErrors(o)}r.valid=a,n.stopRequest(i,a)}},s)),"pending"}}}),t.format=t.validator.format})(jQuery),function(t){var e={};if(t.ajaxPrefilter)t.ajaxPrefilter(function(t,i,s){var r=t.port;"abort"===t.mode&&(e[r]&&e[r].abort(),e[r]=s)});else{var i=t.ajax;t.ajax=function(s){var r=("mode"in s?s:t.ajaxSettings).mode,n=("port"in s?s:t.ajaxSettings).port;return"abort"===r?(e[n]&&e[n].abort(),e[n]=i.apply(this,arguments),e[n]):i.apply(this,arguments)}}}(jQuery),function(t){t.extend(t.fn,{validateDelegate:function(e,i,s){return this.bind(i,function(i){var r=t(i.target);return r.is(e)?s.apply(r,arguments):void 0})}})}(jQuery); -------------------------------------------------------------------------------- /AspNetRoleCustomization/Scripts/jquery.validate.unobtrusive.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 | /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */ 20 | /*global document: false, jQuery: false */ 21 | (function ($) { 22 | var $jQval = $.validator, 23 | adapters, 24 | data_validation = "unobtrusiveValidation"; 25 | function setValidationValues(options, ruleName, value) { 26 | options.rules[ruleName] = value; 27 | if (options.message) { 28 | options.messages[ruleName] = options.message; 29 | } 30 | } 31 | function splitAndTrim(value) { 32 | return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g); 33 | } 34 | function escapeAttributeValue(value) { 35 | // As mentioned on http://api.jquery.com/category/selectors/ 36 | return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1"); 37 | } 38 | function getModelPrefix(fieldName) { 39 | return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); 40 | } 41 | function appendModelPrefix(value, prefix) { 42 | if (value.indexOf("*.") === 0) { 43 | value = value.replace("*.", prefix); 44 | } 45 | return value; 46 | } 47 | function onError(error, inputElement) { // 'this' is the form element 48 | var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"), 49 | replaceAttrValue = container.attr("data-valmsg-replace"), 50 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null; 51 | container.removeClass("field-validation-valid").addClass("field-validation-error"); 52 | error.data("unobtrusiveContainer", container); 53 | if (replace) { 54 | container.empty(); 55 | error.removeClass("input-validation-error").appendTo(container); 56 | } 57 | else { 58 | error.hide(); 59 | } 60 | } 61 | function onErrors(event, validator) { // 'this' is the form element 62 | var container = $(this).find("[data-valmsg-summary=true]"), 63 | list = container.find("ul"); 64 | if (list && list.length && validator.errorList.length) { 65 | list.empty(); 66 | container.addClass("validation-summary-errors").removeClass("validation-summary-valid"); 67 | $.each(validator.errorList, function () { 68 | $("
  • ").html(this.message).appendTo(list); 69 | }); 70 | } 71 | } 72 | function onSuccess(error) { // 'this' is the form element 73 | var container = error.data("unobtrusiveContainer"), 74 | replaceAttrValue = container.attr("data-valmsg-replace"), 75 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null; 76 | if (container) { 77 | container.addClass("field-validation-valid").removeClass("field-validation-error"); 78 | error.removeData("unobtrusiveContainer"); 79 | if (replace) { 80 | container.empty(); 81 | } 82 | } 83 | } 84 | function onReset(event) { // 'this' is the form element 85 | var $form = $(this); 86 | $form.data("validator").resetForm(); 87 | $form.find(".validation-summary-errors") 88 | .addClass("validation-summary-valid") 89 | .removeClass("validation-summary-errors"); 90 | $form.find(".field-validation-error") 91 | .addClass("field-validation-valid") 92 | .removeClass("field-validation-error") 93 | .removeData("unobtrusiveContainer") 94 | .find(">*") // If we were using valmsg-replace, get the underlying error 95 | .removeData("unobtrusiveContainer"); 96 | } 97 | function validationInfo(form) { 98 | var $form = $(form), 99 | result = $form.data(data_validation), 100 | onResetProxy = $.proxy(onReset, form); 101 | if (!result) { 102 | result = { 103 | options: { // options structure passed to jQuery Validate's validate() method 104 | errorClass: "input-validation-error", 105 | errorElement: "span", 106 | errorPlacement: $.proxy(onError, form), 107 | invalidHandler: $.proxy(onErrors, form), 108 | messages: {}, 109 | rules: {}, 110 | success: $.proxy(onSuccess, form) 111 | }, 112 | attachValidation: function () { 113 | $form 114 | .unbind("reset." + data_validation, onResetProxy) 115 | .bind("reset." + data_validation, onResetProxy) 116 | .validate(this.options); 117 | }, 118 | validate: function () { // a validation function that is called by unobtrusive Ajax 119 | $form.validate(); 120 | return $form.valid(); 121 | } 122 | }; 123 | $form.data(data_validation, result); 124 | } 125 | return result; 126 | } 127 | $jQval.unobtrusive = { 128 | adapters: [], 129 | parseElement: function (element, skipAttach) { 130 | /// 131 | /// Parses a single HTML element for unobtrusive validation attributes. 132 | /// 133 | /// The HTML element to be parsed. 134 | /// [Optional] true to skip attaching the 135 | /// validation to the form. If parsing just this single element, you should specify true. 136 | /// If parsing several elements, you should specify false, and manually attach the validation 137 | /// to the form when you are finished. The default is false. 138 | var $element = $(element), 139 | form = $element.parents("form")[0], 140 | valInfo, rules, messages; 141 | if (!form) { // Cannot do client-side validation without a form 142 | return; 143 | } 144 | valInfo = validationInfo(form); 145 | valInfo.options.rules[element.name] = rules = {}; 146 | valInfo.options.messages[element.name] = messages = {}; 147 | $.each(this.adapters, function () { 148 | var prefix = "data-val-" + this.name, 149 | message = $element.attr(prefix), 150 | paramValues = {}; 151 | if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy) 152 | prefix += "-"; 153 | $.each(this.params, function () { 154 | paramValues[this] = $element.attr(prefix + this); 155 | }); 156 | this.adapt({ 157 | element: element, 158 | form: form, 159 | message: message, 160 | params: paramValues, 161 | rules: rules, 162 | messages: messages 163 | }); 164 | } 165 | }); 166 | $.extend(rules, { "__dummy__": true }); 167 | if (!skipAttach) { 168 | valInfo.attachValidation(); 169 | } 170 | }, 171 | parse: function (selector) { 172 | /// 173 | /// Parses all the HTML elements in the specified selector. It looks for input elements decorated 174 | /// with the [data-val=true] attribute value and enables validation according to the data-val-* 175 | /// attribute values. 176 | /// 177 | /// Any valid jQuery selector. 178 | var $forms = $(selector) 179 | .parents("form") 180 | .andSelf() 181 | .add($(selector).find("form")) 182 | .filter("form"); 183 | // :input is a psuedoselector provided by jQuery which selects input and input-like elements 184 | // combining :input with other selectors significantly decreases performance. 185 | $(selector).find(":input").filter("[data-val=true]").each(function () { 186 | $jQval.unobtrusive.parseElement(this, true); 187 | }); 188 | $forms.each(function () { 189 | var info = validationInfo(this); 190 | if (info) { 191 | info.attachValidation(); 192 | } 193 | }); 194 | } 195 | }; 196 | adapters = $jQval.unobtrusive.adapters; 197 | adapters.add = function (adapterName, params, fn) { 198 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation. 199 | /// The name of the adapter to be added. This matches the name used 200 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 201 | /// [Optional] An array of parameter names (strings) that will 202 | /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and 203 | /// mmmm is the parameter name). 204 | /// The function to call, which adapts the values from the HTML 205 | /// attributes into jQuery Validate rules and/or messages. 206 | /// 207 | if (!fn) { // Called with no params, just a function 208 | fn = params; 209 | params = []; 210 | } 211 | this.push({ name: adapterName, params: params, adapt: fn }); 212 | return this; 213 | }; 214 | adapters.addBool = function (adapterName, ruleName) { 215 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 216 | /// the jQuery Validate validation rule has no parameter values. 217 | /// The name of the adapter to be added. This matches the name used 218 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 219 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value 220 | /// of adapterName will be used instead. 221 | /// 222 | return this.add(adapterName, function (options) { 223 | setValidationValues(options, ruleName || adapterName, true); 224 | }); 225 | }; 226 | adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) { 227 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 228 | /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and 229 | /// one for min-and-max). The HTML parameters are expected to be named -min and -max. 230 | /// The name of the adapter to be added. This matches the name used 231 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name). 232 | /// The name of the jQuery Validate rule to be used when you only 233 | /// have a minimum value. 234 | /// The name of the jQuery Validate rule to be used when you only 235 | /// have a maximum value. 236 | /// The name of the jQuery Validate rule to be used when you 237 | /// have both a minimum and maximum value. 238 | /// [Optional] The name of the HTML attribute that 239 | /// contains the minimum value. The default is "min". 240 | /// [Optional] The name of the HTML attribute that 241 | /// contains the maximum value. The default is "max". 242 | /// 243 | return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) { 244 | var min = options.params.min, 245 | max = options.params.max; 246 | if (min && max) { 247 | setValidationValues(options, minMaxRuleName, [min, max]); 248 | } 249 | else if (min) { 250 | setValidationValues(options, minRuleName, min); 251 | } 252 | else if (max) { 253 | setValidationValues(options, maxRuleName, max); 254 | } 255 | }); 256 | }; 257 | adapters.addSingleVal = function (adapterName, attribute, ruleName) { 258 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where 259 | /// the jQuery Validate validation rule has a single value. 260 | /// The name of the adapter to be added. This matches the name used 261 | /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name). 262 | /// [Optional] The name of the HTML attribute that contains the value. 263 | /// The default is "val". 264 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value 265 | /// of adapterName will be used instead. 266 | /// 267 | return this.add(adapterName, [attribute || "val"], function (options) { 268 | setValidationValues(options, ruleName || adapterName, options.params[attribute]); 269 | }); 270 | }; 271 | $jQval.addMethod("__dummy__", function (value, element, params) { 272 | return true; 273 | }); 274 | $jQval.addMethod("regex", function (value, element, params) { 275 | var match; 276 | if (this.optional(element)) { 277 | return true; 278 | } 279 | match = new RegExp(params).exec(value); 280 | return (match && (match.index === 0) && (match[0].length === value.length)); 281 | }); 282 | $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) { 283 | var match; 284 | if (nonalphamin) { 285 | match = value.match(/\W/g); 286 | match = match && match.length >= nonalphamin; 287 | } 288 | return match; 289 | }); 290 | if ($jQval.methods.extension) { 291 | adapters.addSingleVal("accept", "mimtype"); 292 | adapters.addSingleVal("extension", "extension"); 293 | } else { 294 | // for backward compatibility, when the 'extension' validation method does not exist, such as with versions 295 | // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for 296 | // validating the extension, and ignore mime-type validations as they are not supported. 297 | adapters.addSingleVal("extension", "extension", "accept"); 298 | } 299 | adapters.addSingleVal("regex", "pattern"); 300 | adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"); 301 | adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range"); 302 | adapters.add("equalto", ["other"], function (options) { 303 | var prefix = getModelPrefix(options.element.name), 304 | other = options.params.other, 305 | fullOtherName = appendModelPrefix(other, prefix), 306 | element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0]; 307 | setValidationValues(options, "equalTo", element); 308 | }); 309 | adapters.add("required", function (options) { 310 | // jQuery Validate equates "required" with "mandatory" for checkbox elements 311 | if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") { 312 | setValidationValues(options, "required", true); 313 | } 314 | }); 315 | adapters.add("remote", ["url", "type", "additionalfields"], function (options) { 316 | var value = { 317 | url: options.params.url, 318 | type: options.params.type || "GET", 319 | data: {} 320 | }, 321 | prefix = getModelPrefix(options.element.name); 322 | $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) { 323 | var paramName = appendModelPrefix(fieldName, prefix); 324 | value.data[paramName] = function () { 325 | return $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']").val(); 326 | }; 327 | }); 328 | setValidationValues(options, "remote", value); 329 | }); 330 | adapters.add("password", ["min", "nonalphamin", "regex"], function (options) { 331 | if (options.params.min) { 332 | setValidationValues(options, "minlength", options.params.min); 333 | } 334 | if (options.params.nonalphamin) { 335 | setValidationValues(options, "nonalphamin", options.params.nonalphamin); 336 | } 337 | if (options.params.regex) { 338 | setValidationValues(options, "regex", options.params.regex); 339 | } 340 | }); 341 | $(function () { 342 | $jQval.unobtrusive.parse(document); 343 | }); 344 | }(jQuery)); 345 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/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.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); 20 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Scripts/respond.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 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 16 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ 17 | window.matchMedia = window.matchMedia || (function(doc, undefined){ 18 | 19 | var bool, 20 | docElem = doc.documentElement, 21 | refNode = docElem.firstElementChild || docElem.firstChild, 22 | // fakeBody required for 23 | fakeBody = doc.createElement('body'), 24 | div = doc.createElement('div'); 25 | 26 | div.id = 'mq-test-1'; 27 | div.style.cssText = "position:absolute;top:-100em"; 28 | fakeBody.style.background = "none"; 29 | fakeBody.appendChild(div); 30 | 31 | return function(q){ 32 | 33 | div.innerHTML = '­'; 34 | 35 | docElem.insertBefore(fakeBody, refNode); 36 | bool = div.offsetWidth == 42; 37 | docElem.removeChild(fakeBody); 38 | 39 | return { matches: bool, media: q }; 40 | }; 41 | 42 | })(document); 43 | 44 | 45 | 46 | 47 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 48 | (function( win ){ 49 | //exposed namespace 50 | win.respond = {}; 51 | 52 | //define update even in native-mq-supporting browsers, to avoid errors 53 | respond.update = function(){}; 54 | 55 | //expose media query support flag for external use 56 | respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches; 57 | 58 | //if media queries are supported, exit here 59 | if( respond.mediaQueriesSupported ){ return; } 60 | 61 | //define vars 62 | var doc = win.document, 63 | docElem = doc.documentElement, 64 | mediastyles = [], 65 | rules = [], 66 | appendedEls = [], 67 | parsedSheets = {}, 68 | resizeThrottle = 30, 69 | head = doc.getElementsByTagName( "head" )[0] || docElem, 70 | base = doc.getElementsByTagName( "base" )[0], 71 | links = head.getElementsByTagName( "link" ), 72 | requestQueue = [], 73 | 74 | //loop stylesheets, send text content to translate 75 | ripCSS = function(){ 76 | var sheets = links, 77 | sl = sheets.length, 78 | i = 0, 79 | //vars for loop: 80 | sheet, href, media, isCSS; 81 | 82 | for( ; i < sl; i++ ){ 83 | sheet = sheets[ i ], 84 | href = sheet.href, 85 | media = sheet.media, 86 | isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet"; 87 | 88 | //only links plz and prevent re-parsing 89 | if( !!href && isCSS && !parsedSheets[ href ] ){ 90 | // selectivizr exposes css through the rawCssText expando 91 | if (sheet.styleSheet && sheet.styleSheet.rawCssText) { 92 | translate( sheet.styleSheet.rawCssText, href, media ); 93 | parsedSheets[ href ] = true; 94 | } else { 95 | if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) 96 | || href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){ 97 | requestQueue.push( { 98 | href: href, 99 | media: media 100 | } ); 101 | } 102 | } 103 | } 104 | } 105 | makeRequests(); 106 | }, 107 | 108 | //recurse through request queue, get css text 109 | makeRequests = function(){ 110 | if( requestQueue.length ){ 111 | var thisRequest = requestQueue.shift(); 112 | 113 | ajax( thisRequest.href, function( styles ){ 114 | translate( styles, thisRequest.href, thisRequest.media ); 115 | parsedSheets[ thisRequest.href ] = true; 116 | makeRequests(); 117 | } ); 118 | } 119 | }, 120 | 121 | //find media blocks in css text, convert to style blocks 122 | translate = function( styles, href, media ){ 123 | var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ), 124 | ql = qs && qs.length || 0, 125 | //try to get CSS path 126 | href = href.substring( 0, href.lastIndexOf( "/" )), 127 | repUrls = function( css ){ 128 | return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" ); 129 | }, 130 | useMedia = !ql && media, 131 | //vars used in loop 132 | i = 0, 133 | j, fullq, thisq, eachq, eql; 134 | 135 | //if path exists, tack on trailing slash 136 | if( href.length ){ href += "/"; } 137 | 138 | //if no internal queries exist, but media attr does, use that 139 | //note: this currently lacks support for situations where a media attr is specified on a link AND 140 | //its associated stylesheet has internal CSS media queries. 141 | //In those cases, the media attribute will currently be ignored. 142 | if( useMedia ){ 143 | ql = 1; 144 | } 145 | 146 | 147 | for( ; i < ql; i++ ){ 148 | j = 0; 149 | 150 | //media attr 151 | if( useMedia ){ 152 | fullq = media; 153 | rules.push( repUrls( styles ) ); 154 | } 155 | //parse for styles 156 | else{ 157 | fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1; 158 | rules.push( RegExp.$2 && repUrls( RegExp.$2 ) ); 159 | } 160 | 161 | eachq = fullq.split( "," ); 162 | eql = eachq.length; 163 | 164 | for( ; j < eql; j++ ){ 165 | thisq = eachq[ j ]; 166 | mediastyles.push( { 167 | media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all", 168 | rules : rules.length - 1, 169 | hasquery: thisq.indexOf("(") > -1, 170 | minw : thisq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ), 171 | maxw : thisq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ) 172 | } ); 173 | } 174 | } 175 | 176 | applyMedia(); 177 | }, 178 | 179 | lastCall, 180 | 181 | resizeDefer, 182 | 183 | // returns the value of 1em in pixels 184 | getEmValue = function() { 185 | var ret, 186 | div = doc.createElement('div'), 187 | body = doc.body, 188 | fakeUsed = false; 189 | 190 | div.style.cssText = "position:absolute;font-size:1em;width:1em"; 191 | 192 | if( !body ){ 193 | body = fakeUsed = doc.createElement( "body" ); 194 | body.style.background = "none"; 195 | } 196 | 197 | body.appendChild( div ); 198 | 199 | docElem.insertBefore( body, docElem.firstChild ); 200 | 201 | ret = div.offsetWidth; 202 | 203 | if( fakeUsed ){ 204 | docElem.removeChild( body ); 205 | } 206 | else { 207 | body.removeChild( div ); 208 | } 209 | 210 | //also update eminpx before returning 211 | ret = eminpx = parseFloat(ret); 212 | 213 | return ret; 214 | }, 215 | 216 | //cached container for 1em value, populated the first time it's needed 217 | eminpx, 218 | 219 | //enable/disable styles 220 | applyMedia = function( fromResize ){ 221 | var name = "clientWidth", 222 | docElemProp = docElem[ name ], 223 | currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp, 224 | styleBlocks = {}, 225 | lastLink = links[ links.length-1 ], 226 | now = (new Date()).getTime(); 227 | 228 | //throttle resize calls 229 | if( fromResize && lastCall && now - lastCall < resizeThrottle ){ 230 | clearTimeout( resizeDefer ); 231 | resizeDefer = setTimeout( applyMedia, resizeThrottle ); 232 | return; 233 | } 234 | else { 235 | lastCall = now; 236 | } 237 | 238 | for( var i in mediastyles ){ 239 | var thisstyle = mediastyles[ i ], 240 | min = thisstyle.minw, 241 | max = thisstyle.maxw, 242 | minnull = min === null, 243 | maxnull = max === null, 244 | em = "em"; 245 | 246 | if( !!min ){ 247 | min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 248 | } 249 | if( !!max ){ 250 | max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 ); 251 | } 252 | 253 | // 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 254 | if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){ 255 | if( !styleBlocks[ thisstyle.media ] ){ 256 | styleBlocks[ thisstyle.media ] = []; 257 | } 258 | styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] ); 259 | } 260 | } 261 | 262 | //remove any existing respond style element(s) 263 | for( var i in appendedEls ){ 264 | if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){ 265 | head.removeChild( appendedEls[ i ] ); 266 | } 267 | } 268 | 269 | //inject active styles, grouped by media type 270 | for( var i in styleBlocks ){ 271 | var ss = doc.createElement( "style" ), 272 | css = styleBlocks[ i ].join( "\n" ); 273 | 274 | ss.type = "text/css"; 275 | ss.media = i; 276 | 277 | //originally, ss was appended to a documentFragment and sheets were appended in bulk. 278 | //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! 279 | head.insertBefore( ss, lastLink.nextSibling ); 280 | 281 | if ( ss.styleSheet ){ 282 | ss.styleSheet.cssText = css; 283 | } 284 | else { 285 | ss.appendChild( doc.createTextNode( css ) ); 286 | } 287 | 288 | //push to appendedEls to track for later removal 289 | appendedEls.push( ss ); 290 | } 291 | }, 292 | //tweaked Ajax functions from Quirksmode 293 | ajax = function( url, callback ) { 294 | var req = xmlHttp(); 295 | if (!req){ 296 | return; 297 | } 298 | req.open( "GET", url, true ); 299 | req.onreadystatechange = function () { 300 | if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){ 301 | return; 302 | } 303 | callback( req.responseText ); 304 | } 305 | if ( req.readyState == 4 ){ 306 | return; 307 | } 308 | req.send( null ); 309 | }, 310 | //define ajax obj 311 | xmlHttp = (function() { 312 | var xmlhttpmethod = false; 313 | try { 314 | xmlhttpmethod = new XMLHttpRequest(); 315 | } 316 | catch( e ){ 317 | xmlhttpmethod = new ActiveXObject( "Microsoft.XMLHTTP" ); 318 | } 319 | return function(){ 320 | return xmlhttpmethod; 321 | }; 322 | })(); 323 | 324 | //translate CSS 325 | ripCSS(); 326 | 327 | //expose update for re-running respond later on 328 | respond.update = ripCSS; 329 | 330 | //adjust on resize 331 | function callMedia(){ 332 | applyMedia( true ); 333 | } 334 | if( win.addEventListener ){ 335 | win.addEventListener( "resize", callMedia, false ); 336 | } 337 | else if( win.attachEvent ){ 338 | win.attachEvent( "onresize", callMedia ); 339 | } 340 | })(this); 341 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Scripts/respond.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 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 16 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ 17 | 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); 18 | 19 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 20 | (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); -------------------------------------------------------------------------------- /AspNetRoleCustomization/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Owin; 2 | using Owin; 3 | 4 | [assembly: OwinStartupAttribute(typeof(AspNetRoleCustomization.Startup))] 5 | namespace AspNetRoleCustomization 6 | { 7 | public partial class Startup 8 | { 9 | public void Configuration(IAppBuilder app) 10 | { 11 | ConfigureAuth(app); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Account/Delete.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.EditUserViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Delete"; 5 | } 6 | 7 |

    Delete

    8 | 9 |

    Are you sure you want to delete this?

    10 |
    11 |

    EditUserViewModel

    12 |
    13 |
    14 |
    15 | @Html.DisplayNameFor(model => model.UserName) 16 |
    17 | 18 |
    19 | @Html.DisplayFor(model => model.UserName) 20 |
    21 | 22 |
    23 | @Html.DisplayNameFor(model => model.FirstName) 24 |
    25 | 26 |
    27 | @Html.DisplayFor(model => model.FirstName) 28 |
    29 | 30 |
    31 | @Html.DisplayNameFor(model => model.LastName) 32 |
    33 | 34 |
    35 | @Html.DisplayFor(model => model.LastName) 36 |
    37 | 38 |
    39 | @Html.DisplayNameFor(model => model.Email) 40 |
    41 | 42 |
    43 | @Html.DisplayFor(model => model.Email) 44 |
    45 | 46 |
    47 | 48 | @using (Html.BeginForm()) { 49 | @Html.AntiForgeryToken() 50 | 51 |
    52 | | 53 | @Html.ActionLink("Back to List", "Index") 54 |
    55 | } 56 |
    57 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Account/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.EditUserViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Edit"; 5 | } 6 | 7 |

    Edit

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

    EditUserViewModel

    16 |
    17 | @Html.ValidationSummary(true) 18 |
    19 | @Html.LabelFor(model => model.UserName, new { @class = "control-label col-md-2" }) 20 |
    21 | @Html.EditorFor(model => model.UserName) 22 | @Html.ValidationMessageFor(model => model.UserName) 23 |
    24 |
    25 | 26 |
    27 | @Html.LabelFor(model => model.FirstName, new { @class = "control-label col-md-2" }) 28 |
    29 | @Html.EditorFor(model => model.FirstName) 30 | @Html.ValidationMessageFor(model => model.FirstName) 31 |
    32 |
    33 | 34 |
    35 | @Html.LabelFor(model => model.LastName, new { @class = "control-label col-md-2" }) 36 |
    37 | @Html.EditorFor(model => model.LastName) 38 | @Html.ValidationMessageFor(model => model.LastName) 39 |
    40 |
    41 | 42 |
    43 | @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" }) 44 |
    45 | @Html.EditorFor(model => model.Email) 46 | @Html.ValidationMessageFor(model => model.Email) 47 |
    48 |
    49 | 50 |
    51 |
    52 | 53 |
    54 |
    55 |
    56 | } 57 | 58 |
    59 | @Html.ActionLink("Back to List", "Index") 60 |
    61 | 62 | @section Scripts { 63 | @Scripts.Render("~/bundles/jqueryval") 64 | } 65 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Account/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IEnumerable 2 | 3 | @{ 4 | ViewBag.Title = "Users"; 5 | } 6 | 7 |

    Application Users

    8 | 9 |

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

    12 | 13 | 14 | 17 | 20 | 23 | 26 | 27 | 28 | 29 | @foreach (var item in Model) { 30 | 31 | 34 | 37 | 40 | 43 | 49 | 50 | } 51 | 52 |
    15 | @Html.DisplayNameFor(model => model.UserName) 16 | 18 | @Html.DisplayNameFor(model => model.FirstName) 19 | 21 | @Html.DisplayNameFor(model => model.LastName) 22 | 24 | @Html.DisplayNameFor(model => model.Email) 25 |
    32 | @Html.DisplayFor(modelItem => item.UserName) 33 | 35 | @Html.DisplayFor(modelItem => item.FirstName) 36 | 38 | @Html.DisplayFor(modelItem => item.LastName) 39 | 41 | @Html.DisplayFor(modelItem => item.Email) 42 | 44 | @Html.ActionLink("Edit", "Edit", new { id = item.UserName }) | 45 | @Html.ActionLink("Groups", "UserGroups", new { id = item.UserName }) | 46 | @Html.ActionLink("Delete", "Delete", new { id = item.UserName }) 47 | @Html.ActionLink("Effective Permissions", "UserPermissions", new { id = item.UserName }) 48 |
    53 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.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 | { 13 | @Html.AntiForgeryToken() 14 |

    Use a local account to log in.

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

    45 | @Html.ActionLink("Register", "Register") if you don't have a local account. 46 |

    47 | } 48 |
    49 |
    50 |
    51 | @section Scripts { 52 | @Scripts.Render("~/bundles/jqueryval") 53 | } -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Account/Manage.cshtml: -------------------------------------------------------------------------------- 1 | @using AspNetRoleCustomization.Models; 2 | @using Microsoft.AspNet.Identity; 3 | @{ 4 | ViewBag.Title = "Manage Account"; 5 | } 6 | 7 |

    @ViewBag.Title.

    8 | 9 |

    @ViewBag.StatusMessage

    10 |
    11 |
    12 | @if (ViewBag.HasLocalPassword) 13 | { 14 | @Html.Partial("_ChangePasswordPartial") 15 | } 16 | else 17 | { 18 | @Html.Partial("_SetPasswordPartial") 19 | } 20 |
    21 |
    22 | @section Scripts { 23 | @Scripts.Render("~/bundles/jqueryval") 24 | } 25 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Account/Register.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.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() 14 |
    15 | @Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.TextBoxFor(m => m.UserName, 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 | //Add the LastName, FirstName, and Email Properties: 34 |
    35 | @Html.LabelFor(m => m.LastName, new { @class = "col-md-2 control-label" }) 36 |
    37 | @Html.TextBoxFor(m => m.LastName, new { @class = "form-control" }) 38 |
    39 |
    40 | 41 |
    42 | @Html.LabelFor(m => m.FirstName, new { @class = "col-md-2 control-label" }) 43 |
    44 | @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control" }) 45 |
    46 |
    47 | 48 |
    49 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 50 |
    51 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 52 |
    53 |
    54 | 55 |
    56 |
    57 | 58 |
    59 |
    60 | } 61 | 62 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Account/UserGroups.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.SelectUserGroupsViewModel 2 | 3 | @{ 4 | ViewBag.Title = "User Groups"; 5 | } 6 | 7 |

    Group Assignments for user @Html.DisplayFor(model => model.UserName)

    8 |
    9 | 10 | @using (Html.BeginForm("UserGroups", "Account", FormMethod.Post, new { encType = "multipart/form-data", name = "myform" })) 11 | { 12 | @Html.AntiForgeryToken() 13 | 14 |
    15 | @Html.ValidationSummary(true) 16 |
    17 |
    18 | @Html.HiddenFor(model => model.UserName) 19 |
    20 |
    21 | 22 |

    Select Group Assignments for this User

    23 |
    24 |
    25 | 26 | 27 | 28 | 31 | 34 | 35 | 36 | @Html.EditorFor(model => model.Groups) 37 |
    29 | Select 30 | 32 | Group 33 |
    38 |
    39 |
    40 | 41 |
    42 |
    43 | 44 |
    45 |
    46 |
    47 | } 48 | 49 |
    50 | @Html.ActionLink("Back to List", "Index") 51 |
    52 | 53 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Account/UserPermissions.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.UserPermissionsViewModel 2 | @{ 3 | ViewBag.Title = "UserPermissions"; 4 | } 5 | 6 |

    Effective Role Permissions for user: @Html.DisplayFor(model => model.UserName)

    7 |
    8 | 9 | 10 | 11 | 14 | 17 | 18 | 19 | 20 | @foreach (var item in Model.Roles) 21 | { 22 | 23 | 26 | 29 | 30 | } 31 | 32 |
    12 | Role Permission 13 | 15 | Description 16 |
    24 | @Html.DisplayFor(modelItem => item.RoleName) 25 | 27 | @Html.DisplayFor(modelItem => item.Description) 28 |
    33 | 34 |
    35 | @Html.ActionLink("Back to List", "Index") 36 |
    -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Account/_ChangePasswordPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNet.Identity 2 | @model AspNetRoleCustomization.Models.ManageUserViewModel 3 | 4 |

    You're logged in as @User.Identity.GetUserName().

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

    Change Password Form

    10 |
    11 | @Html.ValidationSummary() 12 |
    13 | @Html.LabelFor(m => m.OldPassword, new { @class = "col-md-2 control-label" }) 14 |
    15 | @Html.PasswordFor(m => m.OldPassword, new { @class = "form-control" }) 16 |
    17 |
    18 |
    19 | @Html.LabelFor(m => m.NewPassword, new { @class = "col-md-2 control-label" }) 20 |
    21 | @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" }) 22 |
    23 |
    24 |
    25 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 26 |
    27 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 28 |
    29 |
    30 | 31 |
    32 |
    33 | 34 |
    35 |
    36 | } 37 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Account/_SetPasswordPartial.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.ManageUserViewModel 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("Manage", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 | 12 |

    Create Local Login

    13 |
    14 | @Html.ValidationSummary() 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 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Groups/Create.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.Group 2 | 3 | @{ 4 | ViewBag.Title = "Create Groups"; 5 | } 6 | 7 |

    Create a new Group

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

    Group

    16 |
    17 | @Html.ValidationSummary(true) 18 | 19 |
    20 | @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" }) 21 |
    22 | @Html.EditorFor(model => model.Name) 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 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Groups/Delete.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.Group 2 | 3 | @{ 4 | ViewBag.Title = "Delete"; 5 | } 6 | 7 |

    Delete

    8 | 9 |

    Are you sure you want to delete this?

    10 |
    11 |

    Group

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

    Details

    8 | 9 |
    10 |

    Group

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

    24 | @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) | 25 | @Html.ActionLink("Back to List", "Index") 26 |

    27 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Groups/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.Group 2 | 3 | @{ 4 | ViewBag.Title = "Edit"; 5 | } 6 | 7 |

    Edit

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

    Group

    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.EditorFor(model => model.Name) 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 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Groups/GroupRoles.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.SelectGroupRolesViewModel 2 | 3 | @{ 4 | ViewBag.Title = "Group Roles"; 5 | } 6 | 7 |

    Permissions for Group @Html.DisplayFor(model => model.GroupName)

    8 |
    9 | 10 | @using (Html.BeginForm("GroupRoles", "Groups", FormMethod.Post, new { encType = "multipart/form-data", name = "myform" })) 11 | { 12 | @Html.AntiForgeryToken() 13 | 14 |
    15 | @Html.ValidationSummary(true) 16 |
    17 |
    18 | @Html.HiddenFor(model => model.GroupName) 19 |
    20 |
    21 | 22 |
    23 |
    24 | @Html.HiddenFor(model => model.GroupId) 25 |
    26 |
    27 | 28 |

    Select Role Permissions for this Group

    29 |
    30 |
    31 | 32 | 33 | 34 | 37 | 40 | 41 | 42 | @Html.EditorFor(model => model.Roles) 43 |
    35 | Select 36 | 38 | Group 39 |
    44 |
    45 |
    46 | 47 |
    48 |
    49 | 50 |
    51 |
    52 |
    53 | } 54 | 55 |
    56 | @Html.ActionLink("Back to List", "Index") 57 |
    58 | 59 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Groups/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IEnumerable 2 | 3 | @{ 4 | ViewBag.Title = "Index"; 5 | } 6 | 7 |

    Groups

    8 | 9 |

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

    12 | 13 | 14 | 17 | 18 | 19 | 20 | @foreach (var item in Model) { 21 | 22 | 25 | 30 | 31 | } 32 | 33 |
    15 | @Html.DisplayNameFor(model => model.Name) 16 |
    23 | @Html.DisplayFor(modelItem => item.Name) 24 | 26 | @Html.ActionLink("Edit", "Edit", new { id=item.Id }) | 27 | @Html.ActionLink("Permissions", "GroupRoles", new { id=item.Id }) | 28 | @Html.ActionLink("Delete", "Delete", new { id=item.Id }) 29 |
    34 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "About"; 3 | } 4 |

    @ViewBag.Title.

    5 |

    @ViewBag.Message

    6 | 7 |

    Use this area to provide additional information.

    8 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Home/Contact.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Contact"; 3 | } 4 |

    @ViewBag.Title.

    5 |

    @ViewBag.Message

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

    ASP.NET

    7 |

    ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.

    8 |

    Learn more »

    9 |
    10 | 11 |
    12 |
    13 |

    Getting started

    14 |

    15 | ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that 16 | enables a clean separation of concerns and gives you full control over markup 17 | for enjoyable, agile development. 18 |

    19 |

    Learn more »

    20 |
    21 |
    22 |

    Get more libraries

    23 |

    NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.

    24 |

    Learn more »

    25 |
    26 |
    27 |

    Web Hosting

    28 |

    You can easily find a web hosting company that offers the right mix of features and price for your applications.

    29 |

    Learn more »

    30 |
    31 |
    -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Roles/Create.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.ApplicationRole 2 | 3 | @{ 4 | ViewBag.Title = "Create"; 5 | } 6 | 7 |

    Create

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

    ApplicationRole

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

    Delete

    8 | 9 |

    Are you sure you want to delete this?

    10 |
    11 |

    ApplicationRole

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

    Details

    8 | 9 |
    10 |

    ApplicationRole

    11 |
    12 |
    13 |
    14 | @Html.DisplayNameFor(model => model.Name) 15 |
    16 | 17 |
    18 | @Html.DisplayFor(model => model.Name) 19 |
    20 | 21 |
    22 | @Html.DisplayNameFor(model => model.Description) 23 |
    24 | 25 |
    26 | @Html.DisplayFor(model => model.Description) 27 |
    28 | 29 |
    30 |
    31 |

    32 | @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) | 33 | @Html.ActionLink("Back to List", "Index") 34 |

    35 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Roles/Edit.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.ApplicationRole 2 | 3 | @{ 4 | ViewBag.Title = "Edit"; 5 | } 6 | 7 |

    Edit

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

    ApplicationRole

    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.EditorFor(model => model.Name) 24 | @Html.ValidationMessageFor(model => model.Name) 25 |
    26 |
    27 | 28 |
    29 | @Html.LabelFor(model => model.Description, new { @class = "control-label col-md-2" }) 30 |
    31 | @Html.EditorFor(model => model.Description) 32 | @Html.ValidationMessageFor(model => model.Description) 33 |
    34 |
    35 | 36 |
    37 |
    38 | 39 |
    40 |
    41 |
    42 | } 43 | 44 |
    45 | @Html.ActionLink("Back to List", "Index") 46 |
    47 | 48 | @section Scripts { 49 | @Scripts.Render("~/bundles/jqueryval") 50 | } 51 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Roles/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 | 23 | @foreach (var item in Model) { 24 | 25 | 28 | 31 | 36 | 37 | } 38 | 39 |
    15 | @Html.DisplayNameFor(model => model.Name) 16 | 18 | @Html.DisplayNameFor(model => model.Description) 19 |
    26 | @Html.DisplayFor(modelItem => item.Name) 27 | 29 | @Html.DisplayFor(modelItem => item.Description) 30 | 32 | @Html.ActionLink("Edit", "Edit", new { id=item.Id }) | 33 | @Html.ActionLink("Details", "Details", new { id=item.Id }) | 34 | @Html.ActionLink("Delete", "Delete", new { id=item.Id }) 35 |
    40 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Shared/EditorTemplates/SelectGroupEditorViewModel.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.SelectGroupEditorViewModel 2 | @Html.HiddenFor(model => model.GroupId) 3 | @Html.HiddenFor(model => model.GroupName) 4 | 5 | 6 | @Html.CheckBoxFor(model => model.Selected) 7 | 8 | 9 | @Html.DisplayFor(model => model.GroupName) 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Shared/EditorTemplates/SelectRoleEditorViewModel.cshtml: -------------------------------------------------------------------------------- 1 | @model AspNetRoleCustomization.Models.SelectRoleEditorViewModel 2 | @Html.HiddenFor(model => model.RoleName) 3 | 4 | 5 | @Html.CheckBoxFor(model => model.Selected) 6 | 7 | 8 | @Html.DisplayFor(model => model.RoleName) 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model System.Web.Mvc.HandleErrorInfo 2 | 3 | @{ 4 | ViewBag.Title = "Error"; 5 | } 6 | 7 |

    Error.

    8 |

    An error occurred while processing your request.

    9 | 10 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/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 | 36 |
    37 | @RenderBody() 38 |
    39 |
    40 |

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

    41 |
    42 |
    43 | 44 | @Scripts.Render("~/bundles/jquery") 45 | @Scripts.Render("~/bundles/bootstrap") 46 | @RenderSection("scripts", required: false) 47 | 48 | 49 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNet.Identity 2 | @if (Request.IsAuthenticated) 3 | { 4 | using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" })) 5 | { 6 | @Html.AntiForgeryToken() 7 | 8 | 14 | } 15 | } 16 | else 17 | { 18 | 21 | } 22 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/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 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Web.Debug.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/Web.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/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 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /AspNetRoleCustomization/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xivSolutions/AspNetAdvancedRoleManagement/032526e015a5fd03d2da6e8812624da59b624a08/AspNetRoleCustomization/favicon.ico -------------------------------------------------------------------------------- /AspNetRoleCustomization/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xivSolutions/AspNetAdvancedRoleManagement/032526e015a5fd03d2da6e8812624da59b624a08/AspNetRoleCustomization/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /AspNetRoleCustomization/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xivSolutions/AspNetAdvancedRoleManagement/032526e015a5fd03d2da6e8812624da59b624a08/AspNetRoleCustomization/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /AspNetRoleCustomization/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xivSolutions/AspNetAdvancedRoleManagement/032526e015a5fd03d2da6e8812624da59b624a08/AspNetRoleCustomization/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /AspNetRoleCustomization/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 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ASP.NET Advanced Role-Based Management 2 | ====================================== 3 | 4 | This is an example project to accompany a blog post describing a somewhat more complex approach to managing application authorization by creating groups of roles, to which individual users may be added or removed. 5 | 6 | The objective is to use the `[Authorize]` attribute to establish fine-grained roles at the application level, and then create Groups to which these roles are added. In this way, groups of "premissions" may be configured, and then users can be assigned to one or more of these "role groups," making assignment of application roles potentially parallell real-world user organization roles. 7 | 8 | This project builds upon the foundation created by another example, [ASP.NET Role-Based Security Example][3], covered in the article [Extending Identity Accounts and Implementing Role-Based Authentication in ASP.NET MVC 5][1] 9 | 10 | You will need to enable Nuget Package Restore in Visual Studio in order to download and restore Nuget packages during build. If you are not sure how to do this, see [Keep Nuget Packages Out of Source Control with Nuget Package Manager Restore][2] 11 | 12 | You will also need to run Entity Framework Migrations `Update-Database` command per the article. The migration files are included in the repo, so you will NOT need to `Enable-Migrations` or run `Add-Migration Init`. 13 | 14 | [1]: http://www.typecastexception.com/post/2013/11/11/Extending-Identity-Accounts-and-Implementing-Role-Based-Authentication-in-ASPNET-MVC-5.aspx "Extending Identity Accounts and Implementing Role-Based Authentication in ASP.NET MVC 5" 15 | 16 | [2]: http://www.typecastexception.com/post/2013/11/10/Keep-Nuget-Packages-Out-of-Source-Control-with-Nuget-Package-Manager-Restore.aspx "Keep Nuget Packages Out of Source Control with Nuget Package Manager Restore" 17 | 18 | [3]: https://github.com/xivSolutions/AspNetRoleBasedSecurityExample "ASP.NET Role-Based Security Example" 19 | --------------------------------------------------------------------------------