(), context.Authentication);
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/WebIdentity/Views/Manage/VerifyPhoneNumber.cshtml:
--------------------------------------------------------------------------------
1 | @model WebIdentity.Domain.ViewModels.VerifyPhoneNumberViewModel
2 | @{
3 | ViewBag.Title = "Verify Phone Number";
4 | }
5 |
6 | @ViewBag.Title.
7 |
8 | @using (Html.BeginForm("VerifyPhoneNumber", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
9 | {
10 | @Html.AntiForgeryToken()
11 | @Html.Hidden("phoneNumber", @Model.PhoneNumber)
12 | Enter verification code
13 | @ViewBag.Status
14 |
15 | @Html.ValidationSummary("", new { @class = "text-danger" })
16 |
22 |
27 | }
28 |
29 | @section Scripts {
30 | @Scripts.Render("~/bundles/jqueryval")
31 | }
32 |
--------------------------------------------------------------------------------
/WebIdentity/Views/Account/_ExternalLoginsListPartial.cshtml:
--------------------------------------------------------------------------------
1 | @model WebIdentity.Domain.ViewModels.ExternalLoginListViewModel
2 | @using Microsoft.Owin.Security
3 |
4 | Use another service to log in.
5 |
6 | @{
7 | var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes();
8 | if (loginProviders.Count() == 0) {
9 |
10 |
11 | There are no external authentication services configured. See this article
12 | for details on setting up this ASP.NET application to support logging in via external services.
13 |
14 |
15 | }
16 | else {
17 | using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = Model.ReturnUrl })) {
18 | @Html.AntiForgeryToken()
19 |
20 |
21 | @foreach (AuthenticationDescription p in loginProviders) {
22 | @p.AuthenticationType
23 | }
24 |
25 |
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/WebIdentity/Web.Debug.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/WebIdentity/App_Start/BundleConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Web;
2 | using System.Web.Optimization;
3 |
4 | namespace WebIdentity
5 | {
6 | public class BundleConfig
7 | {
8 | // For more information on bundling, visit https://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 https://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 |
--------------------------------------------------------------------------------
/WebIdentity/Web.Release.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
19 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/WebIdentity/Views/Account/VerifyCode.cshtml:
--------------------------------------------------------------------------------
1 | @model WebIdentity.Domain.ViewModels.VerifyCodeViewModel
2 | @{
3 | ViewBag.Title = "Verify";
4 | }
5 |
6 | @ViewBag.Title.
7 |
8 | @using (Html.BeginForm("VerifyCode", "Account", new { ReturnUrl = Model.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) {
9 | @Html.AntiForgeryToken()
10 | @Html.Hidden("provider", @Model.Provider)
11 | @Html.Hidden("rememberMe", @Model.RememberMe)
12 | Enter verification code
13 |
14 | @Html.ValidationSummary("", new { @class = "text-danger" })
15 |
21 |
29 |
34 | }
35 |
36 | @section Scripts {
37 | @Scripts.Render("~/bundles/jqueryval")
38 | }
39 |
--------------------------------------------------------------------------------
/WebIdentity/Views/Manage/SetPassword.cshtml:
--------------------------------------------------------------------------------
1 | @model WebIdentity.Domain.ViewModels.SetPasswordViewModel
2 | @{
3 | ViewBag.Title = "Create Password";
4 | }
5 |
6 | @ViewBag.Title.
7 |
8 | You do not have a local username/password for this site. Add a local
9 | account so you can log in without an external login.
10 |
11 |
12 | @using (Html.BeginForm("SetPassword", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
13 | {
14 | @Html.AntiForgeryToken()
15 |
16 | Create Local Login
17 |
18 | @Html.ValidationSummary("", new { @class = "text-danger" })
19 |
25 |
31 |
36 | }
37 | @section Scripts {
38 | @Scripts.Render("~/bundles/jqueryval")
39 | }
--------------------------------------------------------------------------------
/WebIdentity/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("WebIdentity")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("WebIdentity")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
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("9344c692-7177-4bc0-9556-3e42744f1cbc")]
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 |
--------------------------------------------------------------------------------
/WebIdentity/Views/Account/ExternalLoginConfirmation.cshtml:
--------------------------------------------------------------------------------
1 | @model WebIdentity.Domain.ViewModels.ExternalLoginConfirmationViewModel
2 | @{
3 | ViewBag.Title = "Register";
4 | }
5 | @ViewBag.Title.
6 | Associate your @ViewBag.LoginProvider account.
7 |
8 | @using (Html.BeginForm("ExternalLoginConfirmation", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
9 | {
10 | @Html.AntiForgeryToken()
11 |
12 | Association Form
13 |
14 | @Html.ValidationSummary(true, "", new { @class = "text-danger" })
15 |
16 | You've successfully authenticated with @ViewBag.LoginProvider .
17 | Please enter a user name for this site below and click the Register button to finish
18 | logging in.
19 |
20 |
27 |
32 | }
33 |
34 | @section Scripts {
35 | @Scripts.Render("~/bundles/jqueryval")
36 | }
37 |
--------------------------------------------------------------------------------
/WebIdentity/Views/Account/Register.cshtml:
--------------------------------------------------------------------------------
1 | @model WebIdentity.Domain.ViewModels.RegisterViewModel
2 | @{
3 | ViewBag.Title = "Register";
4 | }
5 |
6 | @ViewBag.Title.
7 |
8 | @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
9 | {
10 | @Html.AntiForgeryToken()
11 | Create a new account.
12 |
13 | @Html.ValidationSummary("", new { @class = "text-danger" })
14 |
20 |
26 |
32 |
37 | }
38 |
39 | @section Scripts {
40 | @Scripts.Render("~/bundles/jqueryval")
41 | }
42 |
--------------------------------------------------------------------------------
/WebIdentity.Domain/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("WebIdentity.Domain")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("WebIdentity.Domain")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
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("bdee7d9c-1531-476d-904c-6e18a824cee8")]
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 Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/WebIdentity/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 |
--------------------------------------------------------------------------------
/WebIdentity.Domain/App.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 |
--------------------------------------------------------------------------------
/WebIdentity/Views/Manage/ChangePassword.cshtml:
--------------------------------------------------------------------------------
1 | @model WebIdentity.Domain.ViewModels.ChangePasswordViewModel
2 | @{
3 | ViewBag.Title = "Change Password";
4 | }
5 |
6 | @ViewBag.Title.
7 |
8 | @using (Html.BeginForm("ChangePassword", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
9 | {
10 | @Html.AntiForgeryToken()
11 | Change Password Form
12 |
13 | @Html.ValidationSummary("", new { @class = "text-danger" })
14 |
20 |
26 |
32 |
37 | }
38 | @section Scripts {
39 | @Scripts.Render("~/bundles/jqueryval")
40 | }
--------------------------------------------------------------------------------
/WebIdentity/Views/Account/ResetPassword.cshtml:
--------------------------------------------------------------------------------
1 | @model WebIdentity.Domain.ViewModels.ResetPasswordViewModel
2 | @{
3 | ViewBag.Title = "Reset password";
4 | }
5 |
6 | @ViewBag.Title.
7 |
8 | @using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
9 | {
10 | @Html.AntiForgeryToken()
11 | Reset your password.
12 |
13 | @Html.ValidationSummary("", new { @class = "text-danger" })
14 | @Html.HiddenFor(model => model.Code)
15 |
21 |
27 |
33 |
38 | }
39 |
40 | @section Scripts {
41 | @Scripts.Render("~/bundles/jqueryval")
42 | }
43 |
--------------------------------------------------------------------------------
/WebIdentity.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27004.2005
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebIdentity", "WebIdentity\WebIdentity.csproj", "{6504ED2D-1A7D-429E-81D2-967864496284}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebIdentity.Domain", "WebIdentity.Domain\WebIdentity.Domain.csproj", "{BDEE7D9C-1531-476D-904C-6E18A824CEE8}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {6504ED2D-1A7D-429E-81D2-967864496284}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {6504ED2D-1A7D-429E-81D2-967864496284}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {6504ED2D-1A7D-429E-81D2-967864496284}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {6504ED2D-1A7D-429E-81D2-967864496284}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {BDEE7D9C-1531-476D-904C-6E18A824CEE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {BDEE7D9C-1531-476D-904C-6E18A824CEE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {BDEE7D9C-1531-476D-904C-6E18A824CEE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {BDEE7D9C-1531-476D-904C-6E18A824CEE8}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {C3B224FE-47FA-4210-831C-47ED6D00C4FC}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/WebIdentity/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 |
13 |
14 |
22 |
23 |
24 | @Html.ActionLink("Home", "Index", "Home")
25 | @Html.ActionLink("About", "About", "Home")
26 | @Html.ActionLink("Contact", "Contact", "Home")
27 |
28 | @Html.Partial("_LoginPartial")
29 |
30 |
31 |
32 |
33 | @RenderBody()
34 |
35 |
38 |
39 |
40 | @Scripts.Render("~/bundles/jquery")
41 | @Scripts.Render("~/bundles/bootstrap")
42 | @RenderSection("scripts", required: false)
43 |
44 |
45 |
--------------------------------------------------------------------------------
/WebIdentity/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 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/WebIdentity/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 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/WebIdentity/Views/Account/Login.cshtml:
--------------------------------------------------------------------------------
1 | @using WebIdentity.Domain.ViewModels
2 | @model LoginViewModel
3 | @{
4 | ViewBag.Title = "Log in";
5 | }
6 |
7 | @ViewBag.Title.
8 |
60 |
61 | @section Scripts {
62 | @Scripts.Render("~/bundles/jqueryval")
63 | }
--------------------------------------------------------------------------------
/WebIdentity.Domain/ViewModels/ManageViewModels.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.ComponentModel.DataAnnotations;
3 | using Microsoft.AspNet.Identity;
4 | using Microsoft.Owin.Security;
5 |
6 | namespace WebIdentity.Domain.ViewModels
7 | {
8 | public class IndexViewModel
9 | {
10 | public bool HasPassword { get; set; }
11 | public IList Logins { get; set; }
12 | public string PhoneNumber { get; set; }
13 | public bool TwoFactor { get; set; }
14 | public bool BrowserRemembered { get; set; }
15 | }
16 |
17 | public class ManageLoginsViewModel
18 | {
19 | public IList CurrentLogins { get; set; }
20 | public IList OtherLogins { get; set; }
21 | }
22 |
23 | public class FactorViewModel
24 | {
25 | public string Purpose { get; set; }
26 | }
27 |
28 | public class SetPasswordViewModel
29 | {
30 | [Required]
31 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
32 | [DataType(DataType.Password)]
33 | [Display(Name = "New password")]
34 | public string NewPassword { get; set; }
35 |
36 | [DataType(DataType.Password)]
37 | [Display(Name = "Confirm new password")]
38 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
39 | public string ConfirmPassword { get; set; }
40 | }
41 |
42 | public class ChangePasswordViewModel
43 | {
44 | [Required]
45 | [DataType(DataType.Password)]
46 | [Display(Name = "Current password")]
47 | public string OldPassword { get; set; }
48 |
49 | [Required]
50 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
51 | [DataType(DataType.Password)]
52 | [Display(Name = "New password")]
53 | public string NewPassword { get; set; }
54 |
55 | [DataType(DataType.Password)]
56 | [Display(Name = "Confirm new password")]
57 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
58 | public string ConfirmPassword { get; set; }
59 | }
60 |
61 | public class AddPhoneNumberViewModel
62 | {
63 | [Required]
64 | [Phone]
65 | [Display(Name = "Phone Number")]
66 | public string Number { get; set; }
67 | }
68 |
69 | public class VerifyPhoneNumberViewModel
70 | {
71 | [Required]
72 | [Display(Name = "Code")]
73 | public string Code { get; set; }
74 |
75 | [Required]
76 | [Phone]
77 | [Display(Name = "Phone Number")]
78 | public string PhoneNumber { get; set; }
79 | }
80 |
81 | public class ConfigureTwoFactorViewModel
82 | {
83 | public string SelectedProvider { get; set; }
84 | public IDictionary Providers { get; set; }
85 | }
86 | }
--------------------------------------------------------------------------------
/WebIdentity/Views/Manage/ManageLogins.cshtml:
--------------------------------------------------------------------------------
1 | @model WebIdentity.Domain.ViewModels.ManageLoginsViewModel
2 | @using Microsoft.Owin.Security
3 | @{
4 | ViewBag.Title = "Manage your external logins";
5 | }
6 |
7 | @ViewBag.Title.
8 |
9 | @ViewBag.StatusMessage
10 | @{
11 | var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes();
12 | if (loginProviders.Count() == 0) {
13 |
14 |
15 | There are no external authentication services configured. See this article
16 | for details on setting up this ASP.NET application to support logging in via external services.
17 |
18 |
19 | }
20 | else
21 | {
22 | if (Model.CurrentLogins.Count > 0)
23 | {
24 | Registered Logins
25 |
53 | }
54 | if (Model.OtherLogins.Count > 0)
55 | {
56 | using (Html.BeginForm("LinkLogin", "Manage"))
57 | {
58 | @Html.AntiForgeryToken()
59 |
60 |
61 | @foreach (AuthenticationDescription p in Model.OtherLogins)
62 | {
63 | @p.AuthenticationType
64 | }
65 |
66 |
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/WebIdentity.Domain/Repositories/UserManager.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNet.Identity.Owin;
2 | using Microsoft.Owin;
3 | using System;
4 | using System.Threading.Tasks;
5 | using WebIdentity.Domain.Models;
6 | using WebIdentity.Domain.Services;
7 | using Identity = Microsoft.AspNet.Identity;
8 |
9 | namespace WebIdentity.Domain.Repositories
10 | {
11 | public class UserManager : Identity.UserManager
12 | {
13 | public UserManager(Identity.IUserStore store) : base(store)
14 | {
15 | }
16 |
17 | public async Task HasPhoneNumber(int userId)
18 | {
19 | var user = await FindByIdAsync(userId);
20 | if (user != null)
21 | {
22 | return user.PhoneNumber != null;
23 | }
24 | return false;
25 | }
26 | public static UserManager Create(IdentityFactoryOptions options, IOwinContext context)
27 | {
28 | var manager = new UserManager(new UserStore(context.Get()));
29 | // Configure validation logic for usernames
30 | manager.UserValidator = new Identity.UserValidator(manager)
31 | {
32 | AllowOnlyAlphanumericUserNames = false,
33 | RequireUniqueEmail = true
34 | };
35 |
36 | // Configure validation logic for passwords
37 | manager.PasswordValidator = new Identity.PasswordValidator
38 | {
39 | RequiredLength = 6,
40 | RequireNonLetterOrDigit = true,
41 | RequireDigit = true,
42 | RequireLowercase = true,
43 | RequireUppercase = true,
44 | };
45 |
46 | // Configure user lockout defaults
47 | manager.UserLockoutEnabledByDefault = true;
48 | manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
49 | manager.MaxFailedAccessAttemptsBeforeLockout = 5;
50 |
51 | // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
52 | // You can write your own provider and plug it in here.
53 | manager.RegisterTwoFactorProvider("Phone Code", new Identity.PhoneNumberTokenProvider
54 | {
55 | MessageFormat = "Your security code is {0}"
56 | });
57 | manager.RegisterTwoFactorProvider("Email Code", new Identity.EmailTokenProvider
58 | {
59 | Subject = "Security Code",
60 | BodyFormat = "Your security code is {0}"
61 | });
62 | manager.EmailService = new EmailService();
63 | manager.SmsService = new SmsService();
64 | var dataProtectionProvider = options.DataProtectionProvider;
65 | if (dataProtectionProvider != null)
66 | {
67 | manager.UserTokenProvider =
68 | new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity"));
69 | }
70 | return manager;
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/WebIdentity.Domain/Models/ApplicationDbContext.cs:
--------------------------------------------------------------------------------
1 | using IdentityEF = Microsoft.AspNet.Identity.EntityFramework;
2 |
3 | namespace WebIdentity.Domain.Models
4 | {
5 | public class ApplicationDbContext : IdentityEF.IdentityDbContext
6 | {
7 | public ApplicationDbContext() : base("DefaultConnection") { }
8 |
9 | public static ApplicationDbContext Create()
10 | {
11 | return new ApplicationDbContext();
12 | }
13 |
14 | protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
15 | {
16 | modelBuilder.HasDefaultSchema("SEC");
17 |
18 | modelBuilder.Entity().Map(c =>
19 | {
20 | c.ToTable(nameof(UserLogin));
21 | c.Properties(p => new
22 | {
23 | p.UserId,
24 | p.LoginProvider,
25 | p.ProviderKey
26 | });
27 | }).HasKey(p => new { p.LoginProvider, p.ProviderKey, p.UserId });
28 |
29 | // Mapping for ApiRole
30 | modelBuilder.Entity().Map(c =>
31 | {
32 | c.ToTable(nameof(Role));
33 | c.Property(p => p.Id).HasColumnName("RoleId");
34 | c.Properties(p => new
35 | {
36 | p.Name
37 | });
38 | }).HasKey(p => p.Id);
39 |
40 | modelBuilder.Entity()
41 | .HasMany(c => c.Users)
42 | .WithRequired()
43 | .HasForeignKey(c => c.RoleId);
44 |
45 | modelBuilder.Entity().Map(c =>
46 | {
47 | c.ToTable(nameof(User));
48 | c.Property(p => p.Id).HasColumnName("UserId");
49 | c.Properties(p => new
50 | {
51 | p.AccessFailedCount,
52 | p.Email,
53 | p.EmailConfirmed,
54 | p.PasswordHash,
55 | p.PhoneNumber,
56 | p.PhoneNumberConfirmed,
57 | p.TwoFactorEnabled,
58 | p.SecurityStamp,
59 | p.LockoutEnabled,
60 | p.LockoutEndDateUtc,
61 | p.UserName
62 | });
63 | }).HasKey(c => c.Id);
64 | modelBuilder.Entity().HasMany(c => c.Logins).WithOptional().HasForeignKey(c => c.UserId);
65 | modelBuilder.Entity().HasMany(c => c.Claims).WithOptional().HasForeignKey(c => c.UserId);
66 | modelBuilder.Entity().HasMany(c => c.Roles).WithRequired().HasForeignKey(c => c.UserId);
67 |
68 | modelBuilder.Entity().Map(c =>
69 | {
70 | c.ToTable("UserRole");
71 | c.Properties(p => new
72 | {
73 | p.UserId,
74 | p.RoleId
75 | });
76 | })
77 | .HasKey(c => new { c.UserId, c.RoleId });
78 |
79 | modelBuilder.Entity().Map(c =>
80 | {
81 | c.ToTable("UserClaim");
82 | c.Property(p => p.Id).HasColumnName("UserClaimId");
83 | c.Properties(p => new
84 | {
85 | p.UserId,
86 | p.ClaimValue,
87 | p.ClaimType
88 | });
89 | }).HasKey(c => c.Id);
90 | }
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/WebIdentity.Domain/Startup.Auth.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNet.Identity;
2 | using Microsoft.AspNet.Identity.Owin;
3 | using Microsoft.Owin;
4 | using Microsoft.Owin.Security.Cookies;
5 | using Owin;
6 | using System;
7 | using WebIdentity.Domain.Models;
8 | using WebIdentity.Domain.Repositories;
9 |
10 | namespace WebIdentity.Domain
11 | {
12 | public static class Startup
13 | {
14 | public static void ConfigureAuth(this IAppBuilder app)
15 | {
16 | // Configure the db context, user manager and signin manager to use a single instance per request
17 | app.CreatePerOwinContext(ApplicationDbContext.Create);
18 | app.CreatePerOwinContext(UserManager.Create);
19 | app.CreatePerOwinContext(SignInManager.Create);
20 |
21 | // Enable the application to use a cookie to store information for the signed in user
22 | // and to use a cookie to temporarily store information about a user logging in with a third party login provider
23 | // Configure the sign in cookie
24 | app.UseCookieAuthentication(new CookieAuthenticationOptions
25 | {
26 | AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
27 | LoginPath = new PathString("/Account/Login"),
28 | Provider = new CookieAuthenticationProvider
29 | {
30 | // Enables the application to validate the security stamp when the user logs in.
31 | // This is a security feature which is used when you change a password or add an external login to your account.
32 | OnValidateIdentity = SecurityStampValidator
33 | .OnValidateIdentity(
34 | validateInterval: TimeSpan.FromMinutes(30),
35 | regenerateIdentityCallback: (manager, user) =>
36 | user.GenerateUserIdentityAsync(manager),
37 | getUserIdCallback: (id) => (id.GetUserId()))
38 | }
39 | });
40 | app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
41 |
42 | // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
43 | app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
44 |
45 | // Enables the application to remember the second login verification factor such as phone or email.
46 | // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
47 | // This is similar to the RememberMe option when you log in.
48 | app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
49 |
50 | // Uncomment the following lines to enable logging in with third party login providers
51 | //app.UseMicrosoftAccountAuthentication(
52 | // clientId: "",
53 | // clientSecret: "");
54 |
55 | //app.UseTwitterAuthentication(
56 | // consumerKey: "",
57 | // consumerSecret: "");
58 |
59 | //app.UseFacebookAuthentication(
60 | // appId: "",
61 | // appSecret: "");
62 |
63 | //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
64 | //{
65 | // ClientId = "",
66 | // ClientSecret = ""
67 | //});
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/WebIdentity/Views/Manage/Index.cshtml:
--------------------------------------------------------------------------------
1 | @model WebIdentity.Domain.ViewModels.IndexViewModel
2 | @{
3 | ViewBag.Title = "Manage";
4 | }
5 |
6 | @ViewBag.Title.
7 |
8 | @ViewBag.StatusMessage
9 |
10 |
Change your account settings
11 |
12 |
13 | Password:
14 |
15 | [
16 | @if (Model.HasPassword)
17 | {
18 | @Html.ActionLink("Change your password", "ChangePassword")
19 | }
20 | else
21 | {
22 | @Html.ActionLink("Create", "SetPassword")
23 | }
24 | ]
25 |
26 | External Logins:
27 |
28 | @Model.Logins.Count [
29 | @Html.ActionLink("Manage", "ManageLogins") ]
30 |
31 | @*
32 | Phone Numbers can used as a second factor of verification in a two-factor authentication system.
33 |
34 | See this article
35 | for details on setting up this ASP.NET application to support two-factor authentication using SMS.
36 |
37 | Uncomment the following block after you have set up two-factor authentication
38 | *@
39 | @*
40 | Phone Number:
41 |
42 | @(Model.PhoneNumber ?? "None")
43 | @if (Model.PhoneNumber != null)
44 | {
45 |
46 | [ @Html.ActionLink("Change", "AddPhoneNumber") ]
47 | using (Html.BeginForm("RemovePhoneNumber", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
48 | {
49 | @Html.AntiForgeryToken()
50 | [ ]
51 | }
52 | }
53 | else
54 | {
55 | [ @Html.ActionLink("Add", "AddPhoneNumber")
56 | }
57 |
58 | *@
59 | Two-Factor Authentication:
60 |
61 |
62 | There are no two-factor authentication providers configured. See this article
63 | for details on setting up this ASP.NET application to support two-factor authentication.
64 |
65 | @*@if (Model.TwoFactor)
66 | {
67 | using (Html.BeginForm("DisableTwoFactorAuthentication", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
68 | {
69 | @Html.AntiForgeryToken()
70 | Enabled
71 |
72 |
73 | }
74 | }
75 | else
76 | {
77 | using (Html.BeginForm("EnableTwoFactorAuthentication", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
78 | {
79 | @Html.AntiForgeryToken()
80 | Disabled
81 |
82 |
83 | }
84 | }*@
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/WebIdentity.Domain/ViewModels/AccountViewModels.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.ComponentModel.DataAnnotations;
3 |
4 | namespace WebIdentity.Domain.ViewModels
5 | {
6 | public class ExternalLoginConfirmationViewModel
7 | {
8 | [Required]
9 | [Display(Name = "Email")]
10 | public string Email { get; set; }
11 | }
12 |
13 | public class ExternalLoginListViewModel
14 | {
15 | public string ReturnUrl { get; set; }
16 | }
17 |
18 | public class SendCodeViewModel
19 | {
20 | public string SelectedProvider { get; set; }
21 | public List> Providers { get; set; }
22 | public string ReturnUrl { get; set; }
23 | public bool RememberMe { get; set; }
24 | }
25 |
26 | public class VerifyCodeViewModel
27 | {
28 | [Required]
29 | public string Provider { get; set; }
30 |
31 | [Required]
32 | [Display(Name = "Code")]
33 | public string Code { get; set; }
34 | public string ReturnUrl { get; set; }
35 |
36 | [Display(Name = "Remember this browser?")]
37 | public bool RememberBrowser { get; set; }
38 |
39 | public bool RememberMe { get; set; }
40 | }
41 |
42 | public class ForgotViewModel
43 | {
44 | [Required]
45 | [Display(Name = "Email")]
46 | public string Email { get; set; }
47 | }
48 |
49 | public class LoginViewModel
50 | {
51 | [Required]
52 | [Display(Name = "Email")]
53 | [EmailAddress]
54 | public string Email { get; set; }
55 |
56 | [Required]
57 | [DataType(DataType.Password)]
58 | [Display(Name = "Password")]
59 | public string Password { get; set; }
60 |
61 | [Display(Name = "Remember me?")]
62 | public bool RememberMe { get; set; }
63 | }
64 |
65 | public class RegisterViewModel
66 | {
67 | [Required]
68 | [EmailAddress]
69 | [Display(Name = "Email")]
70 | public string Email { get; set; }
71 |
72 | [Required]
73 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
74 | [DataType(DataType.Password)]
75 | [Display(Name = "Password")]
76 | public string Password { get; set; }
77 |
78 | [DataType(DataType.Password)]
79 | [Display(Name = "Confirm password")]
80 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
81 | public string ConfirmPassword { get; set; }
82 | }
83 |
84 | public class ResetPasswordViewModel
85 | {
86 | [Required]
87 | [EmailAddress]
88 | [Display(Name = "Email")]
89 | public string Email { get; set; }
90 |
91 | [Required]
92 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
93 | [DataType(DataType.Password)]
94 | [Display(Name = "Password")]
95 | public string Password { get; set; }
96 |
97 | [DataType(DataType.Password)]
98 | [Display(Name = "Confirm password")]
99 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
100 | public string ConfirmPassword { get; set; }
101 |
102 | public string Code { get; set; }
103 | }
104 |
105 | public class ForgotPasswordViewModel
106 | {
107 | [Required]
108 | [EmailAddress]
109 | [Display(Name = "Email")]
110 | public string Email { get; set; }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/WebIdentity.Domain/Migrations/201711091617341_First.cs:
--------------------------------------------------------------------------------
1 | namespace WebIdentity.Domain.Migrations
2 | {
3 | using System;
4 | using System.Data.Entity.Migrations;
5 |
6 | public partial class First : DbMigration
7 | {
8 | public override void Up()
9 | {
10 | CreateTable(
11 | "SEC.Role",
12 | c => new
13 | {
14 | RoleId = c.Int(nullable: false, identity: true),
15 | Name = c.String(),
16 | })
17 | .PrimaryKey(t => t.RoleId);
18 |
19 | CreateTable(
20 | "SEC.UserRole",
21 | c => new
22 | {
23 | UserId = c.Int(nullable: false),
24 | RoleId = c.Int(nullable: false),
25 | })
26 | .PrimaryKey(t => new { t.UserId, t.RoleId })
27 | .ForeignKey("SEC.Role", t => t.RoleId, cascadeDelete: true)
28 | .ForeignKey("SEC.User", t => t.UserId, cascadeDelete: true)
29 | .Index(t => t.UserId)
30 | .Index(t => t.RoleId);
31 |
32 | CreateTable(
33 | "SEC.User",
34 | c => new
35 | {
36 | UserId = c.Int(nullable: false, identity: true),
37 | Email = c.String(),
38 | EmailConfirmed = c.Boolean(nullable: false),
39 | PasswordHash = c.String(),
40 | SecurityStamp = c.String(),
41 | PhoneNumber = c.String(),
42 | PhoneNumberConfirmed = c.Boolean(nullable: false),
43 | TwoFactorEnabled = c.Boolean(nullable: false),
44 | LockoutEndDateUtc = c.DateTime(),
45 | LockoutEnabled = c.Boolean(nullable: false),
46 | AccessFailedCount = c.Int(nullable: false),
47 | UserName = c.String(),
48 | })
49 | .PrimaryKey(t => t.UserId);
50 |
51 | CreateTable(
52 | "SEC.UserClaim",
53 | c => new
54 | {
55 | UserClaimId = c.Int(nullable: false, identity: true),
56 | UserId = c.Int(nullable: false),
57 | ClaimType = c.String(),
58 | ClaimValue = c.String(),
59 | })
60 | .PrimaryKey(t => t.UserClaimId)
61 | .ForeignKey("SEC.User", t => t.UserId, cascadeDelete: true)
62 | .Index(t => t.UserId);
63 |
64 | CreateTable(
65 | "SEC.UserLogin",
66 | c => new
67 | {
68 | LoginProvider = c.String(nullable: false, maxLength: 128),
69 | ProviderKey = c.String(nullable: false, maxLength: 128),
70 | UserId = c.Int(nullable: false),
71 | })
72 | .PrimaryKey(t => new { t.LoginProvider, t.ProviderKey, t.UserId })
73 | .ForeignKey("SEC.User", t => t.UserId, cascadeDelete: true)
74 | .Index(t => t.UserId);
75 |
76 | }
77 |
78 | public override void Down()
79 | {
80 | DropForeignKey("SEC.UserRole", "UserId", "SEC.User");
81 | DropForeignKey("SEC.UserLogin", "UserId", "SEC.User");
82 | DropForeignKey("SEC.UserClaim", "UserId", "SEC.User");
83 | DropForeignKey("SEC.UserRole", "RoleId", "SEC.Role");
84 | DropIndex("SEC.UserLogin", new[] { "UserId" });
85 | DropIndex("SEC.UserClaim", new[] { "UserId" });
86 | DropIndex("SEC.UserRole", new[] { "RoleId" });
87 | DropIndex("SEC.UserRole", new[] { "UserId" });
88 | DropTable("SEC.UserLogin");
89 | DropTable("SEC.UserClaim");
90 | DropTable("SEC.User");
91 | DropTable("SEC.UserRole");
92 | DropTable("SEC.Role");
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/WebIdentity/Scripts/respond.min.js:
--------------------------------------------------------------------------------
1 | /*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl
2 | * Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT
3 | * */
4 |
5 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b #mq-test-1 { width: 42px; }',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";if(a.matchMedia&&a.matchMedia("all").addListener)return!1;var b=a.matchMedia,c=b("only all").matches,d=!1,e=0,f=[],g=function(){a.clearTimeout(e),e=a.setTimeout(function(){for(var c=0,d=f.length;d>c;c++){var e=f[c].mql,g=f[c].listeners||[],h=b(e.media).matches;if(h!==e.matches){e.matches=h;for(var i=0,j=g.length;j>i;i++)g[i].call(a,e)}}},30)};a.matchMedia=function(e){var h=b(e),i=[],j=0;return h.addListener=function(b){c&&(d||(d=!0,a.addEventListener("resize",g,!0)),0===j&&(j=f.push({mql:h,listeners:i})),i.push(b))},h.removeListener=function(a){for(var b=0,c=i.length;c>b;b++)i[b]===a&&i.splice(b,1)},h}}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b
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 |
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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
--------------------------------------------------------------------------------
/WebIdentity/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),c="__jquery_unobtrusive_validation_form_reset";if(b.data(c))return;b.data(c,true);try{b.data("validator").resetForm()}finally{b.removeData(c)}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(b){var c=a(b),f=c.data(e),i=a.proxy(n,b),g=d.unobtrusive.options||{},h=function(e,d){var c=g[e];c&&a.isFunction(c)&&c.apply(b,d)};if(!f){f={options:{errorClass:g.errorClass||"input-validation-error",errorElement:g.errorElement||"span",errorPlacement:function(){m.apply(b,arguments);h("errorPlacement",arguments)},invalidHandler:function(){l.apply(b,arguments);h("invalidHandler",arguments)},messages:{},rules:{},success:function(){k.apply(b,arguments);h("success",arguments)}},attachValidation:function(){c.off("reset."+e,i).on("reset."+e,i).validate(this.options)},validate:function(){c.validate();return c.valid()}};c.data(e,f)}return f}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(c){var b=a(c),e=b.parents().addBack().filter("form").add(b.find("form")).has("[data-val=true]");b.find("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});e.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){var d=a(b.form).find(":input").filter("[name='"+f(c)+"']");return d.is(":checkbox")?d.filter(":checked").val()||d.filter(":hidden").val()||"":d.is(":radio")?d.filter(":checked").val()||"":d.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);
--------------------------------------------------------------------------------
/WebIdentity.Domain/WebIdentity.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {BDEE7D9C-1531-476D-904C-6E18A824CEE8}
8 | Library
9 | Properties
10 | WebIdentity.Domain
11 | WebIdentity.Domain
12 | v4.6.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll
35 |
36 |
37 | ..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll
38 |
39 |
40 | ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll
41 |
42 |
43 | ..\packages\Microsoft.AspNet.Identity.EntityFramework.2.2.1\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll
44 |
45 |
46 | ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll
47 |
48 |
49 | ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll
50 |
51 |
52 | ..\packages\Microsoft.Owin.Security.3.1.0\lib\net45\Microsoft.Owin.Security.dll
53 |
54 |
55 | ..\packages\Microsoft.Owin.Security.Cookies.2.1.0\lib\net45\Microsoft.Owin.Security.Cookies.dll
56 |
57 |
58 | ..\packages\Microsoft.Owin.Security.OAuth.2.1.0\lib\net45\Microsoft.Owin.Security.OAuth.dll
59 |
60 |
61 | ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll
62 |
63 |
64 | ..\packages\Owin.1.0\lib\net40\Owin.dll
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | 201711091617341_First.cs
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 | 201711091617341_First.cs
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/WebIdentity.Domain/Migrations/201711091617341_First.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 | H4sIAAAAAAAEAO1cW2/kNBR+R+I/RHkCVJq2+wLVzK7KtIWK7UU7XeBt5Uk804jECYlTWiF+GQ/8JP4Cx7mNr5kkk8kMEkJCO758Puf4i31sf7v//PX35N1LGFjPOEn9iEzt0+MT28LEjTyfrKZ2Rpdff2O/e/v5Z5MrL3yxfqravWHtoCdJp/YTpfG546TuEw5Rehz6bhKl0ZIeu1HoIC9yzk5OvnVOTx0MEDZgWdbkQ0aoH+L8B/ycRcTFMc1QcBt5OEjLcqiZ56jWHQpxGiMXT+2f8eLGw9Cdvh5fRiHyyXHRybYuAh+BQXMcLG0LERJRRMHc848pntMkIqt5DAUoeHyNMbRboiDFpRvn6+ZtPTo5Yx45644VlJulFAzrBnj6pgyRI3fvFWi7DiEE8SqPFvM6D+TU/hAF4Lg80PksSFijhhgfs55Hllp/VHMDKMT+O7JmWUCzBE8JzmiCgiPrIVsEvvsjfn2MfsVkSrIg4M0EQ6FOKICihySKcUJfP+BlafyNZ1uO2M+RO9bduD6FazeEvjmzrTsYHC0CXLOAC8OcRgn+HhOcIIq9B0QpTgjDKDxWRpfGYv+vRgPawYdkW7fo5T0mK/o0teGPtnXtv2CvKikt+Eh8+O6gE00yrAxyh579VW6fNByQOwHuf8BBXps++XHxCeRz9amsvk6ikP0u5r4o/TSPssRltkZK1SNKVpiKVkycNZEa6cUg+lOs6r1nmjEzVKppmzJr+7CyGqKZmc1sq8Zuj9FpGvtP4f+rRONYVxCPYPhlQjcK7K5LPwlx7d13EZAGkc5ce0Bp+nuUeD+g9Gnnps+xmyUQyDlFYbzz0R6eIoLvsnDBKD/eWINNzePv0TVygZJXhPXaGu995P4aZfSKeJdA74/UrQDZz0c/bA8wiDkXrovT9BrIjL1ZBMnjdosmW59G3qZnAfJD/T7NrPlU1a83aq5Y2an5Ot1W3WTJ+2jlkwZLqnrJkqJYb0lZ19UShtBgSFkt2ZGX6s0oqrZOXfK49t/48u7/7347z3zyODOAnS/Y+Ug/oSAbeqhOtMw/sv60zLvvmZa5DVD87Htsn22RWleNAb5Ve33Wvpn8kmXGWT49+6bVLHfNrHg3xx68+8do4u1Fmkaun9OSW+LLM6hoA2QWlvlAWkSgOsRCEICQfgwUhEEhDrZMhHtyiQNMsXXhFjcuM5S6yFNdB8O9FoZUewhnyPpQKxrzlTIGsBEn7BNDLPVO4QvyCVWp6xPXj1FgjILUo+U6z3ysseWaSxxjwr5+o8dtBtUfd9nANb4U9E0RmTgcc5oJxSdLponUZk7iTI5EKV2eJllSZhs7IZUmECOwSuN0m1GNFy6j0arMfBsnU06D90crKemWLCmzhd3RSgzEWLQSnf5v0Ko4xzTOpXSo2R+pxCPUeNufGoWxGCV4fGCEKrIs6EOhB06qy5CYRT9vfLlglfiFas4FYGd5NEjLxFCeeQY+x1Q8ja8zOyEDc5o7V/TQAayp0wLEBNCqc3WJokUoN9oWMNUNiBamXFglGG4CxYhWDzBcA/V5RmZSY3JcW1xPmcLExpyW68/NmrxQiA61cFa4xVK9NeZtGzM3yd5mf3UJlwRQ2TiMxxVXDB7rUoqNSUV3j6VcQAKobBzG45IwBoc1m92m7a67u+IutSWhq8NsvczWdROnkB+UBRPHoFOY3KI4hsM6p1soS6x5IVqYfT3v/owfFhiOm2pe82tr65FolKAVlmphaLD02k9SeokoWiB2lJ95odJMu6kYlspqSH7fUGesWjur1uzPRY9meYFmEy4hrsHBkG3f+e2jtA6q3SwmH0EBSjQXnbMoyELSfJ41IxRvBzxGUaIiTBzJdiVpUAKlZGxi1FvNyfo7GGZe6i28+9yYu5qiWyVYfHxNSZcZpZrVdjO9x3kaco56zk//b6f7vJQP3zxIWdQRg3s7VcC4uvao4vM2jynWtEeU3rB5SKmqg5X8S7VgJF/RC88QUX2L9iOob9M8ulrbHlnzSs1Da6p7YGtsluvao2oesnlgTXV77PWrtvyFHuDuZDwK9F36iuNdv/XP0LfLIphDdFsJh9nnuGdQHogr7ohVPnQqYGX5QbHIeLzqy6LidN+PRYa+5gVGeHIU15fGd1IzpvCOKKzhTe+oZrxuFN0pEZRjmtykHr0+rknHskl5RNqsMVfOTEUT26rCCPv3a0pxeMwaHM9/C2aBj9lqXTW4RcRf4pQW7+X22cnpmaRPPxytuJOmXqA5Ym4WjN8QD79M7T+sP/uoAfrKZkXJq8/CvlGO0vFJnBeHkWeUuE8o+SJEL1/ySFvqOXYS09FVy3n4zU6wLufWzS+fil5H1n0CX8e5dQLubSd1bjtw0avDwNvqo3cxgb1mZeiPQpAsd/gqDEiK9nXh00EkyVuZppUdb4WokRYPhTdICE3S4T5YRtmwBz9pLhvu5qxeRtzHNKOEOP9WthQQ72qPMElRt19jDOeVdgtN3XmHq83ethlFV7rV16pqR3fFFZM+dDuu/Mckm1VwVd3k9orMwbBHovbgKs19CTPX2fK4eswt1ZCddCgDjHdA6st9apjKPXNkmeWW0qFOXDFddR6i+K2FpnKfZCk3zZHFk2OSxXSjeYhk2ayU3CdXxt6CxmZK6y1o7wpIVdNieDEQri8NysbibheKrmYwu0U21Unz2Ch51KF3EkQa9ZAm5PZKyWahpAm/o46yWUZpGmR8laUirNwoQ1N6Ged1j2pKxcCNbgnUkJ5ID0g02d0xgY7Sq93BaCO7uzUEDTtoINVHNFjeuX/OCbaW1F+tIdg/7kSwKyzsdZsbsoyq/UWyqGoinZ1vMUUerPoXCfWXyKVQze718r8qmV+zsNvlBfZuyH1G44yCyzhcBMJVBNunmsbPhZ6izZP7OP8r6kO4AGb67D70nnyX+YFX232tOcIbINgGWN61sbmk7M5t9Voj3UWkJVAZvnrffsRhHABYek/m6Bn3sQ3o9x6vkPu6vpsxgWyeCDHsk0sfrRIUpiXGuj/8BA574cvbfwElQylu1UwAAA==
122 |
123 |
124 | SEC
125 |
126 |
--------------------------------------------------------------------------------
/WebIdentity/Scripts/respond.js:
--------------------------------------------------------------------------------
1 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
2 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
3 | (function(w) {
4 | "use strict";
5 | w.matchMedia = w.matchMedia || function(doc, undefined) {
6 | var bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement("body"), div = doc.createElement("div");
7 | div.id = "mq-test-1";
8 | div.style.cssText = "position:absolute;top:-100em";
9 | fakeBody.style.background = "none";
10 | fakeBody.appendChild(div);
11 | return function(q) {
12 | div.innerHTML = '';
13 | docElem.insertBefore(fakeBody, refNode);
14 | bool = div.offsetWidth === 42;
15 | docElem.removeChild(fakeBody);
16 | return {
17 | matches: bool,
18 | media: q
19 | };
20 | };
21 | }(w.document);
22 | })(this);
23 |
24 | /*! Respond.js v1.4.0: min/max-width media query polyfill. (c) Scott Jehl. MIT Lic. j.mp/respondjs */
25 | (function(w) {
26 | "use strict";
27 | var respond = {};
28 | w.respond = respond;
29 | respond.update = function() {};
30 | var requestQueue = [], xmlHttp = function() {
31 | var xmlhttpmethod = false;
32 | try {
33 | xmlhttpmethod = new w.XMLHttpRequest();
34 | } catch (e) {
35 | xmlhttpmethod = new w.ActiveXObject("Microsoft.XMLHTTP");
36 | }
37 | return function() {
38 | return xmlhttpmethod;
39 | };
40 | }(), ajax = function(url, callback) {
41 | var req = xmlHttp();
42 | if (!req) {
43 | return;
44 | }
45 | req.open("GET", url, true);
46 | req.onreadystatechange = function() {
47 | if (req.readyState !== 4 || req.status !== 200 && req.status !== 304) {
48 | return;
49 | }
50 | callback(req.responseText);
51 | };
52 | if (req.readyState === 4) {
53 | return;
54 | }
55 | req.send(null);
56 | };
57 | respond.ajax = ajax;
58 | respond.queue = requestQueue;
59 | respond.regex = {
60 | media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,
61 | keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,
62 | urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,
63 | findStyles: /@media *([^\{]+)\{([\S\s]+?)$/,
64 | only: /(only\s+)?([a-zA-Z]+)\s?/,
65 | minw: /\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,
66 | maxw: /\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/
67 | };
68 | respond.mediaQueriesSupported = w.matchMedia && w.matchMedia("only all") !== null && w.matchMedia("only all").matches;
69 | if (respond.mediaQueriesSupported) {
70 | return;
71 | }
72 | var doc = w.document, docElem = doc.documentElement, mediastyles = [], rules = [], appendedEls = [], parsedSheets = {}, resizeThrottle = 30, head = doc.getElementsByTagName("head")[0] || docElem, base = doc.getElementsByTagName("base")[0], links = head.getElementsByTagName("link"), lastCall, resizeDefer, eminpx, getEmValue = function() {
73 | var ret, div = doc.createElement("div"), body = doc.body, originalHTMLFontSize = docElem.style.fontSize, originalBodyFontSize = body && body.style.fontSize, fakeUsed = false;
74 | div.style.cssText = "position:absolute;font-size:1em;width:1em";
75 | if (!body) {
76 | body = fakeUsed = doc.createElement("body");
77 | body.style.background = "none";
78 | }
79 | docElem.style.fontSize = "100%";
80 | body.style.fontSize = "100%";
81 | body.appendChild(div);
82 | if (fakeUsed) {
83 | docElem.insertBefore(body, docElem.firstChild);
84 | }
85 | ret = div.offsetWidth;
86 | if (fakeUsed) {
87 | docElem.removeChild(body);
88 | } else {
89 | body.removeChild(div);
90 | }
91 | docElem.style.fontSize = originalHTMLFontSize;
92 | if (originalBodyFontSize) {
93 | body.style.fontSize = originalBodyFontSize;
94 | }
95 | ret = eminpx = parseFloat(ret);
96 | return ret;
97 | }, applyMedia = function(fromResize) {
98 | var name = "clientWidth", docElemProp = docElem[name], currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now = new Date().getTime();
99 | if (fromResize && lastCall && now - lastCall < resizeThrottle) {
100 | w.clearTimeout(resizeDefer);
101 | resizeDefer = w.setTimeout(applyMedia, resizeThrottle);
102 | return;
103 | } else {
104 | lastCall = now;
105 | }
106 | for (var i in mediastyles) {
107 | if (mediastyles.hasOwnProperty(i)) {
108 | var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em";
109 | if (!!min) {
110 | min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
111 | }
112 | if (!!max) {
113 | max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
114 | }
115 | if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
116 | if (!styleBlocks[thisstyle.media]) {
117 | styleBlocks[thisstyle.media] = [];
118 | }
119 | styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
120 | }
121 | }
122 | }
123 | for (var j in appendedEls) {
124 | if (appendedEls.hasOwnProperty(j)) {
125 | if (appendedEls[j] && appendedEls[j].parentNode === head) {
126 | head.removeChild(appendedEls[j]);
127 | }
128 | }
129 | }
130 | appendedEls.length = 0;
131 | for (var k in styleBlocks) {
132 | if (styleBlocks.hasOwnProperty(k)) {
133 | var ss = doc.createElement("style"), css = styleBlocks[k].join("\n");
134 | ss.type = "text/css";
135 | ss.media = k;
136 | head.insertBefore(ss, lastLink.nextSibling);
137 | if (ss.styleSheet) {
138 | ss.styleSheet.cssText = css;
139 | } else {
140 | ss.appendChild(doc.createTextNode(css));
141 | }
142 | appendedEls.push(ss);
143 | }
144 | }
145 | }, translate = function(styles, href, media) {
146 | var qs = styles.replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
147 | href = href.substring(0, href.lastIndexOf("/"));
148 | var repUrls = function(css) {
149 | return css.replace(respond.regex.urls, "$1" + href + "$2$3");
150 | }, useMedia = !ql && media;
151 | if (href.length) {
152 | href += "/";
153 | }
154 | if (useMedia) {
155 | ql = 1;
156 | }
157 | for (var i = 0; i < ql; i++) {
158 | var fullq, thisq, eachq, eql;
159 | if (useMedia) {
160 | fullq = media;
161 | rules.push(repUrls(styles));
162 | } else {
163 | fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1;
164 | rules.push(RegExp.$2 && repUrls(RegExp.$2));
165 | }
166 | eachq = fullq.split(",");
167 | eql = eachq.length;
168 | for (var j = 0; j < eql; j++) {
169 | thisq = eachq[j];
170 | mediastyles.push({
171 | media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all",
172 | rules: rules.length - 1,
173 | hasquery: thisq.indexOf("(") > -1,
174 | minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
175 | maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "")
176 | });
177 | }
178 | }
179 | applyMedia();
180 | }, makeRequests = function() {
181 | if (requestQueue.length) {
182 | var thisRequest = requestQueue.shift();
183 | ajax(thisRequest.href, function(styles) {
184 | translate(styles, thisRequest.href, thisRequest.media);
185 | parsedSheets[thisRequest.href] = true;
186 | w.setTimeout(function() {
187 | makeRequests();
188 | }, 0);
189 | });
190 | }
191 | }, ripCSS = function() {
192 | for (var i = 0; i < links.length; i++) {
193 | var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
194 | if (!!href && isCSS && !parsedSheets[href]) {
195 | if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
196 | translate(sheet.styleSheet.rawCssText, href, media);
197 | parsedSheets[href] = true;
198 | } else {
199 | if (!/^([a-zA-Z:]*\/\/)/.test(href) && !base || href.replace(RegExp.$1, "").split("/")[0] === w.location.host) {
200 | if (href.substring(0, 2) === "//") {
201 | href = w.location.protocol + href;
202 | }
203 | requestQueue.push({
204 | href: href,
205 | media: media
206 | });
207 | }
208 | }
209 | }
210 | }
211 | makeRequests();
212 | };
213 | ripCSS();
214 | respond.update = ripCSS;
215 | respond.getEmValue = getEmValue;
216 | function callMedia() {
217 | applyMedia(true);
218 | }
219 | if (w.addEventListener) {
220 | w.addEventListener("resize", callMedia, false);
221 | } else if (w.attachEvent) {
222 | w.attachEvent("onresize", callMedia);
223 | }
224 | })(this);
--------------------------------------------------------------------------------
/WebIdentity/Scripts/respond.matchmedia.addListener.js:
--------------------------------------------------------------------------------
1 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
2 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
3 | (function(w) {
4 | "use strict";
5 | w.matchMedia = w.matchMedia || function(doc, undefined) {
6 | var bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement("body"), div = doc.createElement("div");
7 | div.id = "mq-test-1";
8 | div.style.cssText = "position:absolute;top:-100em";
9 | fakeBody.style.background = "none";
10 | fakeBody.appendChild(div);
11 | return function(q) {
12 | div.innerHTML = '';
13 | docElem.insertBefore(fakeBody, refNode);
14 | bool = div.offsetWidth === 42;
15 | docElem.removeChild(fakeBody);
16 | return {
17 | matches: bool,
18 | media: q
19 | };
20 | };
21 | }(w.document);
22 | })(this);
23 |
24 | /*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */
25 | (function(w) {
26 | "use strict";
27 | if (w.matchMedia && w.matchMedia("all").addListener) {
28 | return false;
29 | }
30 | var localMatchMedia = w.matchMedia, hasMediaQueries = localMatchMedia("only all").matches, isListening = false, timeoutID = 0, queries = [], handleChange = function(evt) {
31 | w.clearTimeout(timeoutID);
32 | timeoutID = w.setTimeout(function() {
33 | for (var i = 0, il = queries.length; i < il; i++) {
34 | var mql = queries[i].mql, listeners = queries[i].listeners || [], matches = localMatchMedia(mql.media).matches;
35 | if (matches !== mql.matches) {
36 | mql.matches = matches;
37 | for (var j = 0, jl = listeners.length; j < jl; j++) {
38 | listeners[j].call(w, mql);
39 | }
40 | }
41 | }
42 | }, 30);
43 | };
44 | w.matchMedia = function(media) {
45 | var mql = localMatchMedia(media), listeners = [], index = 0;
46 | mql.addListener = function(listener) {
47 | if (!hasMediaQueries) {
48 | return;
49 | }
50 | if (!isListening) {
51 | isListening = true;
52 | w.addEventListener("resize", handleChange, true);
53 | }
54 | if (index === 0) {
55 | index = queries.push({
56 | mql: mql,
57 | listeners: listeners
58 | });
59 | }
60 | listeners.push(listener);
61 | };
62 | mql.removeListener = function(listener) {
63 | for (var i = 0, il = listeners.length; i < il; i++) {
64 | if (listeners[i] === listener) {
65 | listeners.splice(i, 1);
66 | }
67 | }
68 | };
69 | return mql;
70 | };
71 | })(this);
72 |
73 | /*! Respond.js v1.4.0: min/max-width media query polyfill. (c) Scott Jehl. MIT Lic. j.mp/respondjs */
74 | (function(w) {
75 | "use strict";
76 | var respond = {};
77 | w.respond = respond;
78 | respond.update = function() {};
79 | var requestQueue = [], xmlHttp = function() {
80 | var xmlhttpmethod = false;
81 | try {
82 | xmlhttpmethod = new w.XMLHttpRequest();
83 | } catch (e) {
84 | xmlhttpmethod = new w.ActiveXObject("Microsoft.XMLHTTP");
85 | }
86 | return function() {
87 | return xmlhttpmethod;
88 | };
89 | }(), ajax = function(url, callback) {
90 | var req = xmlHttp();
91 | if (!req) {
92 | return;
93 | }
94 | req.open("GET", url, true);
95 | req.onreadystatechange = function() {
96 | if (req.readyState !== 4 || req.status !== 200 && req.status !== 304) {
97 | return;
98 | }
99 | callback(req.responseText);
100 | };
101 | if (req.readyState === 4) {
102 | return;
103 | }
104 | req.send(null);
105 | };
106 | respond.ajax = ajax;
107 | respond.queue = requestQueue;
108 | respond.regex = {
109 | media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,
110 | keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,
111 | urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,
112 | findStyles: /@media *([^\{]+)\{([\S\s]+?)$/,
113 | only: /(only\s+)?([a-zA-Z]+)\s?/,
114 | minw: /\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,
115 | maxw: /\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/
116 | };
117 | respond.mediaQueriesSupported = w.matchMedia && w.matchMedia("only all") !== null && w.matchMedia("only all").matches;
118 | if (respond.mediaQueriesSupported) {
119 | return;
120 | }
121 | var doc = w.document, docElem = doc.documentElement, mediastyles = [], rules = [], appendedEls = [], parsedSheets = {}, resizeThrottle = 30, head = doc.getElementsByTagName("head")[0] || docElem, base = doc.getElementsByTagName("base")[0], links = head.getElementsByTagName("link"), lastCall, resizeDefer, eminpx, getEmValue = function() {
122 | var ret, div = doc.createElement("div"), body = doc.body, originalHTMLFontSize = docElem.style.fontSize, originalBodyFontSize = body && body.style.fontSize, fakeUsed = false;
123 | div.style.cssText = "position:absolute;font-size:1em;width:1em";
124 | if (!body) {
125 | body = fakeUsed = doc.createElement("body");
126 | body.style.background = "none";
127 | }
128 | docElem.style.fontSize = "100%";
129 | body.style.fontSize = "100%";
130 | body.appendChild(div);
131 | if (fakeUsed) {
132 | docElem.insertBefore(body, docElem.firstChild);
133 | }
134 | ret = div.offsetWidth;
135 | if (fakeUsed) {
136 | docElem.removeChild(body);
137 | } else {
138 | body.removeChild(div);
139 | }
140 | docElem.style.fontSize = originalHTMLFontSize;
141 | if (originalBodyFontSize) {
142 | body.style.fontSize = originalBodyFontSize;
143 | }
144 | ret = eminpx = parseFloat(ret);
145 | return ret;
146 | }, applyMedia = function(fromResize) {
147 | var name = "clientWidth", docElemProp = docElem[name], currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now = new Date().getTime();
148 | if (fromResize && lastCall && now - lastCall < resizeThrottle) {
149 | w.clearTimeout(resizeDefer);
150 | resizeDefer = w.setTimeout(applyMedia, resizeThrottle);
151 | return;
152 | } else {
153 | lastCall = now;
154 | }
155 | for (var i in mediastyles) {
156 | if (mediastyles.hasOwnProperty(i)) {
157 | var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em";
158 | if (!!min) {
159 | min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
160 | }
161 | if (!!max) {
162 | max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
163 | }
164 | if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
165 | if (!styleBlocks[thisstyle.media]) {
166 | styleBlocks[thisstyle.media] = [];
167 | }
168 | styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
169 | }
170 | }
171 | }
172 | for (var j in appendedEls) {
173 | if (appendedEls.hasOwnProperty(j)) {
174 | if (appendedEls[j] && appendedEls[j].parentNode === head) {
175 | head.removeChild(appendedEls[j]);
176 | }
177 | }
178 | }
179 | appendedEls.length = 0;
180 | for (var k in styleBlocks) {
181 | if (styleBlocks.hasOwnProperty(k)) {
182 | var ss = doc.createElement("style"), css = styleBlocks[k].join("\n");
183 | ss.type = "text/css";
184 | ss.media = k;
185 | head.insertBefore(ss, lastLink.nextSibling);
186 | if (ss.styleSheet) {
187 | ss.styleSheet.cssText = css;
188 | } else {
189 | ss.appendChild(doc.createTextNode(css));
190 | }
191 | appendedEls.push(ss);
192 | }
193 | }
194 | }, translate = function(styles, href, media) {
195 | var qs = styles.replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
196 | href = href.substring(0, href.lastIndexOf("/"));
197 | var repUrls = function(css) {
198 | return css.replace(respond.regex.urls, "$1" + href + "$2$3");
199 | }, useMedia = !ql && media;
200 | if (href.length) {
201 | href += "/";
202 | }
203 | if (useMedia) {
204 | ql = 1;
205 | }
206 | for (var i = 0; i < ql; i++) {
207 | var fullq, thisq, eachq, eql;
208 | if (useMedia) {
209 | fullq = media;
210 | rules.push(repUrls(styles));
211 | } else {
212 | fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1;
213 | rules.push(RegExp.$2 && repUrls(RegExp.$2));
214 | }
215 | eachq = fullq.split(",");
216 | eql = eachq.length;
217 | for (var j = 0; j < eql; j++) {
218 | thisq = eachq[j];
219 | mediastyles.push({
220 | media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all",
221 | rules: rules.length - 1,
222 | hasquery: thisq.indexOf("(") > -1,
223 | minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
224 | maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "")
225 | });
226 | }
227 | }
228 | applyMedia();
229 | }, makeRequests = function() {
230 | if (requestQueue.length) {
231 | var thisRequest = requestQueue.shift();
232 | ajax(thisRequest.href, function(styles) {
233 | translate(styles, thisRequest.href, thisRequest.media);
234 | parsedSheets[thisRequest.href] = true;
235 | w.setTimeout(function() {
236 | makeRequests();
237 | }, 0);
238 | });
239 | }
240 | }, ripCSS = function() {
241 | for (var i = 0; i < links.length; i++) {
242 | var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
243 | if (!!href && isCSS && !parsedSheets[href]) {
244 | if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
245 | translate(sheet.styleSheet.rawCssText, href, media);
246 | parsedSheets[href] = true;
247 | } else {
248 | if (!/^([a-zA-Z:]*\/\/)/.test(href) && !base || href.replace(RegExp.$1, "").split("/")[0] === w.location.host) {
249 | if (href.substring(0, 2) === "//") {
250 | href = w.location.protocol + href;
251 | }
252 | requestQueue.push({
253 | href: href,
254 | media: media
255 | });
256 | }
257 | }
258 | }
259 | }
260 | makeRequests();
261 | };
262 | ripCSS();
263 | respond.update = ripCSS;
264 | respond.getEmValue = getEmValue;
265 | function callMedia() {
266 | applyMedia(true);
267 | }
268 | if (w.addEventListener) {
269 | w.addEventListener("resize", callMedia, false);
270 | } else if (w.attachEvent) {
271 | w.attachEvent("onresize", callMedia);
272 | }
273 | })(this);
--------------------------------------------------------------------------------
/WebIdentity/Controllers/ManageController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using System.Web;
5 | using System.Web.Mvc;
6 | using Identity = Microsoft.AspNet.Identity;
7 | using Microsoft.AspNet.Identity.Owin;
8 | using Microsoft.Owin.Security;
9 | using WebIdentity.Domain.Models;
10 | using WebIdentity.Domain.Repositories;
11 | using WebIdentity.Domain.ViewModels;
12 | using Microsoft.AspNet.Identity;
13 |
14 | namespace WebIdentity.Controllers
15 | {
16 | [Authorize]
17 | public class ManageController : Controller
18 | {
19 | public ManageController()
20 | {
21 | }
22 | public ManageController(UserManager userManager, SignInManager signInManager)
23 | {
24 | UserManager = userManager;
25 | SignInManager = signInManager;
26 | }
27 |
28 | private UserManager _userManager;
29 | public UserManager UserManager
30 | {
31 | get
32 | {
33 | return _userManager ?? HttpContext.GetOwinContext().GetUserManager();
34 | }
35 | private set
36 | {
37 | _userManager = value;
38 | }
39 | }
40 | private SignInManager _signInManager;
41 | public SignInManager SignInManager
42 | {
43 | get
44 | {
45 | return _signInManager ?? HttpContext.GetOwinContext().Get();
46 | }
47 | private set { _signInManager = value; }
48 | }
49 |
50 |
51 | //
52 | // GET: /Manage/Index
53 | public async Task Index(ManageMessageId? message)
54 | {
55 | ViewBag.StatusMessage =
56 | message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
57 | : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
58 | : message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
59 | : message == ManageMessageId.Error ? "An error has occurred."
60 | : message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
61 | : message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
62 | : "";
63 |
64 | var userId = User.Identity.GetUserId();
65 | var model = new IndexViewModel
66 | {
67 | HasPassword = HasPassword(),
68 | PhoneNumber = await UserManager.GetPhoneNumberAsync(userId),
69 | TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId),
70 | Logins = await UserManager.GetLoginsAsync(userId),
71 | BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId.ToString())
72 | };
73 | return View(model);
74 | }
75 |
76 | //
77 | // POST: /Manage/RemoveLogin
78 | [HttpPost]
79 | [ValidateAntiForgeryToken]
80 | public async Task RemoveLogin(string loginProvider, string providerKey)
81 | {
82 | ManageMessageId? message;
83 | var result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey));
84 | if (result.Succeeded)
85 | {
86 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
87 | if (user != null)
88 | {
89 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
90 | }
91 | message = ManageMessageId.RemoveLoginSuccess;
92 | }
93 | else
94 | {
95 | message = ManageMessageId.Error;
96 | }
97 | return RedirectToAction("ManageLogins", new { Message = message });
98 | }
99 |
100 | //
101 | // GET: /Manage/AddPhoneNumber
102 | public ActionResult AddPhoneNumber()
103 | {
104 | return View();
105 | }
106 |
107 | //
108 | // POST: /Manage/AddPhoneNumber
109 | [HttpPost]
110 | [ValidateAntiForgeryToken]
111 | public async Task AddPhoneNumber(AddPhoneNumberViewModel model)
112 | {
113 | if (!ModelState.IsValid)
114 | {
115 | return View(model);
116 | }
117 | // Generate the token and send it
118 | var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), model.Number);
119 | if (UserManager.SmsService != null)
120 | {
121 | var message = new IdentityMessage
122 | {
123 | Destination = model.Number,
124 | Body = "Your security code is: " + code
125 | };
126 | await UserManager.SmsService.SendAsync(message);
127 | }
128 | return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number });
129 | }
130 |
131 | //
132 | // POST: /Manage/EnableTwoFactorAuthentication
133 | [HttpPost]
134 | [ValidateAntiForgeryToken]
135 | public async Task EnableTwoFactorAuthentication()
136 | {
137 | await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
138 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
139 | if (user != null)
140 | {
141 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
142 | }
143 | return RedirectToAction("Index", "Manage");
144 | }
145 |
146 | //
147 | // POST: /Manage/DisableTwoFactorAuthentication
148 | [HttpPost]
149 | [ValidateAntiForgeryToken]
150 | public async Task DisableTwoFactorAuthentication()
151 | {
152 | await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), false);
153 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
154 | if (user != null)
155 | {
156 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
157 | }
158 | return RedirectToAction("Index", "Manage");
159 | }
160 |
161 | //
162 | // GET: /Manage/VerifyPhoneNumber
163 | public async Task VerifyPhoneNumber(string phoneNumber)
164 | {
165 | var code = await UserManager.GenerateChangePhoneNumberTokenAsync(User.Identity.GetUserId(), phoneNumber);
166 | // Send an SMS through the SMS provider to verify the phone number
167 | return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
168 | }
169 |
170 | //
171 | // POST: /Manage/VerifyPhoneNumber
172 | [HttpPost]
173 | [ValidateAntiForgeryToken]
174 | public async Task VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
175 | {
176 | if (!ModelState.IsValid)
177 | {
178 | return View(model);
179 | }
180 | var result = await UserManager.ChangePhoneNumberAsync(User.Identity.GetUserId(), model.PhoneNumber, model.Code);
181 | if (result.Succeeded)
182 | {
183 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
184 | if (user != null)
185 | {
186 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
187 | }
188 | return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess });
189 | }
190 | // If we got this far, something failed, redisplay form
191 | ModelState.AddModelError("", "Failed to verify phone");
192 | return View(model);
193 | }
194 |
195 | //
196 | // POST: /Manage/RemovePhoneNumber
197 | [HttpPost]
198 | [ValidateAntiForgeryToken]
199 | public async Task RemovePhoneNumber()
200 | {
201 | var result = await UserManager.SetPhoneNumberAsync(User.Identity.GetUserId(), null);
202 | if (!result.Succeeded)
203 | {
204 | return RedirectToAction("Index", new { Message = ManageMessageId.Error });
205 | }
206 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
207 | if (user != null)
208 | {
209 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
210 | }
211 | return RedirectToAction("Index", new { Message = ManageMessageId.RemovePhoneSuccess });
212 | }
213 |
214 | //
215 | // GET: /Manage/ChangePassword
216 | public ActionResult ChangePassword()
217 | {
218 | return View();
219 | }
220 |
221 | //
222 | // POST: /Manage/ChangePassword
223 | [HttpPost]
224 | [ValidateAntiForgeryToken]
225 | public async Task ChangePassword(ChangePasswordViewModel model)
226 | {
227 | if (!ModelState.IsValid)
228 | {
229 | return View(model);
230 | }
231 | var result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword);
232 | if (result.Succeeded)
233 | {
234 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
235 | if (user != null)
236 | {
237 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
238 | }
239 | return RedirectToAction("Index", new { Message = ManageMessageId.ChangePasswordSuccess });
240 | }
241 | AddErrors(result);
242 | return View(model);
243 | }
244 |
245 | //
246 | // GET: /Manage/SetPassword
247 | public ActionResult SetPassword()
248 | {
249 | return View();
250 | }
251 |
252 | //
253 | // POST: /Manage/SetPassword
254 | [HttpPost]
255 | [ValidateAntiForgeryToken]
256 | public async Task SetPassword(SetPasswordViewModel model)
257 | {
258 | if (ModelState.IsValid)
259 | {
260 | var result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
261 | if (result.Succeeded)
262 | {
263 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
264 | if (user != null)
265 | {
266 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
267 | }
268 | return RedirectToAction("Index", new { Message = ManageMessageId.SetPasswordSuccess });
269 | }
270 | AddErrors(result);
271 | }
272 |
273 | // If we got this far, something failed, redisplay form
274 | return View(model);
275 | }
276 |
277 | //
278 | // GET: /Manage/ManageLogins
279 | public async Task ManageLogins(ManageMessageId? message)
280 | {
281 | ViewBag.StatusMessage =
282 | message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
283 | : message == ManageMessageId.Error ? "An error has occurred."
284 | : "";
285 | var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
286 | if (user == null)
287 | {
288 | return View("Error");
289 | }
290 | var userLogins = await UserManager.GetLoginsAsync(User.Identity.GetUserId());
291 | var otherLogins = AuthenticationManager.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList();
292 | ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1;
293 | return View(new ManageLoginsViewModel
294 | {
295 | CurrentLogins = userLogins,
296 | OtherLogins = otherLogins
297 | });
298 | }
299 |
300 | //
301 | // POST: /Manage/LinkLogin
302 | [HttpPost]
303 | [ValidateAntiForgeryToken]
304 | public ActionResult LinkLogin(string provider)
305 | {
306 | // Request a redirect to the external login provider to link a login for the current user
307 | return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage"), User.Identity.GetUserId());
308 | }
309 |
310 | //
311 | // GET: /Manage/LinkLoginCallback
312 | public async Task LinkLoginCallback()
313 | {
314 | var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
315 | if (loginInfo == null)
316 | {
317 | return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
318 | }
319 | var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
320 | return result.Succeeded ? RedirectToAction("ManageLogins") : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
321 | }
322 |
323 | protected override void Dispose(bool disposing)
324 | {
325 | if (disposing && UserManager != null)
326 | {
327 | UserManager.Dispose();
328 | UserManager = null;
329 | }
330 |
331 | base.Dispose(disposing);
332 | }
333 |
334 | #region Helpers
335 | // Used for XSRF protection when adding external logins
336 | private const string XsrfKey = "XsrfId";
337 |
338 | private IAuthenticationManager AuthenticationManager
339 | {
340 | get
341 | {
342 | return HttpContext.GetOwinContext().Authentication;
343 | }
344 | }
345 |
346 | private void AddErrors(IdentityResult result)
347 | {
348 | foreach (var error in result.Errors)
349 | {
350 | ModelState.AddModelError("", error);
351 | }
352 | }
353 |
354 | private bool HasPassword()
355 | {
356 | return UserManager.HasPassword(User.Identity.GetUserId());
357 | }
358 |
359 | private bool HasPhoneNumber()
360 | {
361 | return UserManager.HasPhoneNumber(User.Identity.GetUserId()).Result;
362 | }
363 |
364 | public enum ManageMessageId
365 | {
366 | AddPhoneSuccess,
367 | ChangePasswordSuccess,
368 | SetTwoFactorSuccess,
369 | SetPasswordSuccess,
370 | RemoveLoginSuccess,
371 | RemovePhoneSuccess,
372 | Error
373 | }
374 |
375 | #endregion
376 | }
377 | }
--------------------------------------------------------------------------------
/WebIdentity/Controllers/AccountController.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Threading.Tasks;
3 | using System.Web;
4 | using System.Web.Mvc;
5 | using WebIdentity.Domain.Models;
6 | using WebIdentity.Domain.Repositories;
7 | using WebIdentity.Domain.ViewModels;
8 | using Microsoft.AspNet.Identity.Owin;
9 | using System.Collections.Generic;
10 | using Microsoft.Owin.Security;
11 |
12 | namespace WebIdentity.Controllers
13 | {
14 | [Authorize]
15 | public class AccountController : Controller
16 | {
17 | public AccountController()
18 | {
19 | }
20 | public AccountController(UserManager userManager,SignInManager signInManager )
21 | {
22 | UserManager = userManager;
23 | SignInManager = signInManager;
24 | }
25 |
26 | private UserManager _userManager;
27 | public UserManager UserManager
28 | {
29 | get
30 | {
31 | return _userManager ?? HttpContext.GetOwinContext().GetUserManager();
32 | }
33 | private set
34 | {
35 | _userManager = value;
36 | }
37 | }
38 | private SignInManager _signInManager;
39 | public SignInManager SignInManager
40 | {
41 | get
42 | {
43 | return _signInManager ?? HttpContext.GetOwinContext().Get();
44 | }
45 | private set { _signInManager = value; }
46 | }
47 |
48 | //
49 | // GET: /Account/Login
50 | [AllowAnonymous]
51 | public ActionResult Login(string returnUrl)
52 | {
53 | ViewBag.ReturnUrl = returnUrl;
54 | return View();
55 | }
56 |
57 | //
58 | // POST: /Account/Login
59 | [HttpPost]
60 | [AllowAnonymous]
61 | [ValidateAntiForgeryToken]
62 | public async Task Login(LoginViewModel model, string returnUrl)
63 | {
64 | if (!ModelState.IsValid)
65 | {
66 | return View(model);
67 | }
68 |
69 | // This doesn't count login failures towards account lockout
70 | // To enable password failures to trigger account lockout, change to shouldLockout: true
71 | var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
72 | switch (result)
73 | {
74 | case SignInStatus.Success:
75 | return RedirectToLocal(returnUrl);
76 | case SignInStatus.LockedOut:
77 | return View("Lockout");
78 | case SignInStatus.RequiresVerification:
79 | return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
80 | case SignInStatus.Failure:
81 | default:
82 | ModelState.AddModelError("", "Invalid login attempt.");
83 | return View(model);
84 | }
85 | }
86 |
87 | //
88 | // GET: /Account/VerifyCode
89 | [AllowAnonymous]
90 | public async Task VerifyCode(string provider, string returnUrl, bool rememberMe)
91 | {
92 | // Require that the user has already logged in via username/password or external login
93 | if (!await SignInManager.HasBeenVerifiedAsync())
94 | {
95 | return View("Error");
96 | }
97 | return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
98 | }
99 |
100 | //
101 | // POST: /Account/VerifyCode
102 | [HttpPost]
103 | [AllowAnonymous]
104 | [ValidateAntiForgeryToken]
105 | public async Task VerifyCode(VerifyCodeViewModel model)
106 | {
107 | if (!ModelState.IsValid)
108 | {
109 | return View(model);
110 | }
111 |
112 | // The following code protects for brute force attacks against the two factor codes.
113 | // If a user enters incorrect codes for a specified amount of time then the user account
114 | // will be locked out for a specified amount of time.
115 | // You can configure the account lockout settings in IdentityConfig
116 | var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: model.RememberMe, rememberBrowser: model.RememberBrowser);
117 | switch (result)
118 | {
119 | case SignInStatus.Success:
120 | return RedirectToLocal(model.ReturnUrl);
121 | case SignInStatus.LockedOut:
122 | return View("Lockout");
123 | case SignInStatus.Failure:
124 | default:
125 | ModelState.AddModelError("", "Invalid code.");
126 | return View(model);
127 | }
128 | }
129 |
130 | //
131 | // GET: /Account/Register
132 | [AllowAnonymous]
133 | public ActionResult Register()
134 | {
135 | return View();
136 | }
137 |
138 | //
139 | // POST: /Account/Register
140 | [HttpPost]
141 | [AllowAnonymous]
142 | [ValidateAntiForgeryToken]
143 | public async Task Register(RegisterViewModel model)
144 | {
145 | if (ModelState.IsValid)
146 | {
147 | var user = new User { UserName = model.Email, Email = model.Email };
148 | var result = await UserManager.CreateAsync(user, model.Password);
149 | if (result.Succeeded)
150 | {
151 | await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
152 |
153 | // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
154 | // Send an email with this link
155 | // string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
156 | // var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
157 | // await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here ");
158 |
159 | return RedirectToAction("Index", "Home");
160 | }
161 | AddErrors(result);
162 | }
163 |
164 | // If we got this far, something failed, redisplay form
165 | return View(model);
166 | }
167 |
168 | //
169 | // GET: /Account/ConfirmEmail
170 | [AllowAnonymous]
171 | public async Task ConfirmEmail(int userId, string code)
172 | {
173 | if (userId == default(int) || code == null)
174 | {
175 | return View("Error");
176 | }
177 | var result = await UserManager.ConfirmEmailAsync(userId, code);
178 | return View(result.Succeeded ? "ConfirmEmail" : "Error");
179 | }
180 |
181 | //
182 | // GET: /Account/ForgotPassword
183 | [AllowAnonymous]
184 | public ActionResult ForgotPassword()
185 | {
186 | return View();
187 | }
188 |
189 | //
190 | // POST: /Account/ForgotPassword
191 | [HttpPost]
192 | [AllowAnonymous]
193 | [ValidateAntiForgeryToken]
194 | public async Task ForgotPassword(ForgotPasswordViewModel model)
195 | {
196 | if (ModelState.IsValid)
197 | {
198 | var user = await UserManager.FindByNameAsync(model.Email);
199 | if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
200 | {
201 | // Don't reveal that the user does not exist or is not confirmed
202 | return View("ForgotPasswordConfirmation");
203 | }
204 |
205 | // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
206 | // Send an email with this link
207 | // string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
208 | // var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
209 | // await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking here ");
210 | // return RedirectToAction("ForgotPasswordConfirmation", "Account");
211 | }
212 |
213 | // If we got this far, something failed, redisplay form
214 | return View(model);
215 | }
216 |
217 | //
218 | // GET: /Account/ForgotPasswordConfirmation
219 | [AllowAnonymous]
220 | public ActionResult ForgotPasswordConfirmation()
221 | {
222 | return View();
223 | }
224 |
225 | //
226 | // GET: /Account/ResetPassword
227 | [AllowAnonymous]
228 | public ActionResult ResetPassword(string code)
229 | {
230 | return code == null ? View("Error") : View();
231 | }
232 |
233 | //
234 | // POST: /Account/ResetPassword
235 | [HttpPost]
236 | [AllowAnonymous]
237 | [ValidateAntiForgeryToken]
238 | public async Task ResetPassword(ResetPasswordViewModel model)
239 | {
240 | if (!ModelState.IsValid)
241 | {
242 | return View(model);
243 | }
244 | var user = await UserManager.FindByNameAsync(model.Email);
245 | if (user == null)
246 | {
247 | // Don't reveal that the user does not exist
248 | return RedirectToAction("ResetPasswordConfirmation", "Account");
249 | }
250 | var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
251 | if (result.Succeeded)
252 | {
253 | return RedirectToAction("ResetPasswordConfirmation", "Account");
254 | }
255 | AddErrors(result);
256 | return View();
257 | }
258 |
259 | //
260 | // GET: /Account/ResetPasswordConfirmation
261 | [AllowAnonymous]
262 | public ActionResult ResetPasswordConfirmation()
263 | {
264 | return View();
265 | }
266 |
267 | //
268 | // POST: /Account/ExternalLogin
269 | [HttpPost]
270 | [AllowAnonymous]
271 | [ValidateAntiForgeryToken]
272 | public ActionResult ExternalLogin(string provider, string returnUrl)
273 | {
274 | // Request a redirect to the external login provider
275 | return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
276 | }
277 |
278 | //
279 | // GET: /Account/SendCode
280 | [AllowAnonymous]
281 | public async Task SendCode(string returnUrl, bool rememberMe)
282 | {
283 | var userId = await SignInManager.GetVerifiedUserIdAsync();
284 | if (userId == default(int))
285 | {
286 | return View("Error");
287 | }
288 | var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(userId);
289 |
290 | var factorOptions = userFactors.Select(purpose => new KeyValuePair(purpose, purpose)).ToList();
291 | return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe });
292 | }
293 |
294 | //
295 | // POST: /Account/SendCode
296 | [HttpPost]
297 | [AllowAnonymous]
298 | [ValidateAntiForgeryToken]
299 | public async Task SendCode(SendCodeViewModel model)
300 | {
301 | if (!ModelState.IsValid)
302 | {
303 | return View();
304 | }
305 |
306 | // Generate the token and send it
307 | if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider))
308 | {
309 | return View("Error");
310 | }
311 | return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
312 | }
313 |
314 | //
315 | // GET: /Account/ExternalLoginCallback
316 | [AllowAnonymous]
317 | public async Task ExternalLoginCallback(string returnUrl)
318 | {
319 | var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
320 | if (loginInfo == null)
321 | {
322 | return RedirectToAction("Login");
323 | }
324 |
325 | // Sign in the user with this external login provider if the user already has a login
326 | var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
327 | switch (result)
328 | {
329 | case SignInStatus.Success:
330 | return RedirectToLocal(returnUrl);
331 | case SignInStatus.LockedOut:
332 | return View("Lockout");
333 | case SignInStatus.RequiresVerification:
334 | return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
335 | case SignInStatus.Failure:
336 | default:
337 | // If the user does not have an account, then prompt the user to create an account
338 | ViewBag.ReturnUrl = returnUrl;
339 | ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
340 | return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
341 | }
342 | }
343 |
344 | //
345 | // POST: /Account/ExternalLoginConfirmation
346 | [HttpPost]
347 | [AllowAnonymous]
348 | [ValidateAntiForgeryToken]
349 | public async Task ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
350 | {
351 | if (User.Identity.IsAuthenticated)
352 | {
353 | return RedirectToAction("Index", "Manage");
354 | }
355 |
356 | if (ModelState.IsValid)
357 | {
358 | // Get the information about the user from the external login provider
359 | var info = await AuthenticationManager.GetExternalLoginInfoAsync();
360 | if (info == null)
361 | {
362 | return View("ExternalLoginFailure");
363 | }
364 | var user = new User { UserName = model.Email, Email = model.Email };
365 | var result = await UserManager.CreateAsync(user);
366 | if (result.Succeeded)
367 | {
368 | result = await UserManager.AddLoginAsync(user.Id, info.Login);
369 | if (result.Succeeded)
370 | {
371 | await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
372 | return RedirectToLocal(returnUrl);
373 | }
374 | }
375 | AddErrors(result);
376 | }
377 |
378 | ViewBag.ReturnUrl = returnUrl;
379 | return View(model);
380 | }
381 |
382 | //
383 | // POST: /Account/LogOff
384 | [HttpPost]
385 | [ValidateAntiForgeryToken]
386 | public ActionResult LogOff()
387 | {
388 | AuthenticationManager.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
389 | return RedirectToAction("Index", "Home");
390 | }
391 |
392 | //
393 | // GET: /Account/ExternalLoginFailure
394 | [AllowAnonymous]
395 | public ActionResult ExternalLoginFailure()
396 | {
397 | return View();
398 | }
399 |
400 | protected override void Dispose(bool disposing)
401 | {
402 | if (disposing)
403 | {
404 | if (UserManager != null)
405 | {
406 | UserManager.Dispose();
407 | UserManager = null;
408 | }
409 |
410 | if (SignInManager != null)
411 | {
412 | SignInManager.Dispose();
413 | SignInManager = null;
414 | }
415 | }
416 |
417 | base.Dispose(disposing);
418 | }
419 |
420 | #region Helpers
421 | // Used for XSRF protection when adding external logins
422 | private const string XsrfKey = "XsrfId";
423 |
424 | private IAuthenticationManager AuthenticationManager
425 | {
426 | get
427 | {
428 | return HttpContext.GetOwinContext().Authentication;
429 | }
430 | }
431 |
432 | private void AddErrors(Microsoft.AspNet.Identity.IdentityResult result)
433 | {
434 | foreach (var error in result.Errors)
435 | {
436 | ModelState.AddModelError("", error);
437 | }
438 | }
439 |
440 | private ActionResult RedirectToLocal(string returnUrl)
441 | {
442 | if (Url.IsLocalUrl(returnUrl))
443 | {
444 | return Redirect(returnUrl);
445 | }
446 | return RedirectToAction("Index", "Home");
447 | }
448 |
449 | internal class ChallengeResult : HttpUnauthorizedResult
450 | {
451 | public ChallengeResult(string provider, string redirectUri)
452 | : this(provider, redirectUri, null)
453 | {
454 | }
455 |
456 | public ChallengeResult(string provider, string redirectUri, int? userId)
457 | {
458 | LoginProvider = provider;
459 | RedirectUri = redirectUri;
460 | UserId = userId;
461 | }
462 |
463 | public string LoginProvider { get; set; }
464 | public string RedirectUri { get; set; }
465 | public int? UserId { get; set; }
466 |
467 | public override void ExecuteResult(ControllerContext context)
468 | {
469 | var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
470 | if (UserId != null)
471 | {
472 | properties.Dictionary[XsrfKey] = UserId.Value.ToString();
473 | }
474 | context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
475 | }
476 | }
477 | #endregion
478 | }
479 | }
--------------------------------------------------------------------------------
/WebIdentity/WebIdentity.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Debug
8 | AnyCPU
9 |
10 |
11 | 2.0
12 | {6504ED2D-1A7D-429E-81D2-967864496284}
13 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
14 | Library
15 | Properties
16 | WebIdentity
17 | WebIdentity
18 | v4.6.1
19 | false
20 | true
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | true
32 | full
33 | false
34 | bin\
35 | DEBUG;TRACE
36 | prompt
37 | 4
38 |
39 |
40 | true
41 | pdbonly
42 | true
43 | bin\
44 | TRACE
45 | prompt
46 | 4
47 |
48 |
49 |
50 | ..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll
51 |
52 |
53 | ..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll
54 |
55 |
56 | ..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll
57 |
58 |
59 | ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.8\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll
60 |
61 |
62 |
63 | ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll
64 |
65 |
66 | ..\packages\Microsoft.Owin.Host.SystemWeb.3.1.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll
67 |
68 |
69 | ..\packages\Microsoft.Owin.Security.3.1.0\lib\net45\Microsoft.Owin.Security.dll
70 |
71 |
72 | ..\packages\Microsoft.Owin.Security.Cookies.3.1.0\lib\net45\Microsoft.Owin.Security.Cookies.dll
73 |
74 |
75 | ..\packages\Microsoft.Owin.Security.Facebook.3.1.0\lib\net45\Microsoft.Owin.Security.Facebook.dll
76 |
77 |
78 | ..\packages\Microsoft.Owin.Security.Google.3.1.0\lib\net45\Microsoft.Owin.Security.Google.dll
79 |
80 |
81 | ..\packages\Microsoft.Owin.Security.MicrosoftAccount.3.1.0\lib\net45\Microsoft.Owin.Security.MicrosoftAccount.dll
82 |
83 |
84 | ..\packages\Microsoft.Owin.Security.OAuth.3.1.0\lib\net45\Microsoft.Owin.Security.OAuth.dll
85 |
86 |
87 | ..\packages\Microsoft.Owin.Security.Twitter.3.1.0\lib\net45\Microsoft.Owin.Security.Twitter.dll
88 |
89 |
90 | ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | True
112 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll
113 |
114 |
115 |
116 |
117 |
118 |
119 | True
120 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll
121 |
122 |
123 | True
124 | ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll
125 |
126 |
127 | ..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll
128 |
129 |
130 | True
131 | ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll
132 |
133 |
134 | True
135 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll
136 |
137 |
138 | True
139 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll
140 |
141 |
142 | True
143 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll
144 |
145 |
146 | ..\packages\WebGrease.1.6.0\lib\WebGrease.dll
147 |
148 |
149 |
150 |
151 | ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll
152 |
153 |
154 | ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll
155 |
156 |
157 | ..\packages\Microsoft.AspNet.Identity.EntityFramework.2.2.1\lib\net45\Microsoft.AspNet.Identity.EntityFramework.dll
158 |
159 |
160 | ..\packages\Owin.1.0\lib\net40\Owin.dll
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | Global.asax
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 | Web.config
213 |
214 |
215 | Web.config
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
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 | Designer
252 |
253 |
254 |
255 |
256 |
257 |
258 | {bdee7d9c-1531-476d-904c-6e18a824cee8}
259 | WebIdentity.Domain
260 |
261 |
262 |
263 | 10.0
264 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 | True
277 | True
278 | 50881
279 | /
280 | http://localhost:50881/
281 | False
282 | False
283 |
284 |
285 | False
286 |
287 |
288 |
289 |
290 |
291 |
292 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
293 |
294 |
295 |
296 |
297 |
303 |
--------------------------------------------------------------------------------
/WebIdentity/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 |
20 | /*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 */
21 | /*global document: false, jQuery: false */
22 |
23 | (function ($) {
24 | var $jQval = $.validator,
25 | adapters,
26 | data_validation = "unobtrusiveValidation";
27 |
28 | function setValidationValues(options, ruleName, value) {
29 | options.rules[ruleName] = value;
30 | if (options.message) {
31 | options.messages[ruleName] = options.message;
32 | }
33 | }
34 |
35 | function splitAndTrim(value) {
36 | return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
37 | }
38 |
39 | function escapeAttributeValue(value) {
40 | // As mentioned on http://api.jquery.com/category/selectors/
41 | return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
42 | }
43 |
44 | function getModelPrefix(fieldName) {
45 | return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
46 | }
47 |
48 | function appendModelPrefix(value, prefix) {
49 | if (value.indexOf("*.") === 0) {
50 | value = value.replace("*.", prefix);
51 | }
52 | return value;
53 | }
54 |
55 | function onError(error, inputElement) { // 'this' is the form element
56 | var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
57 | replaceAttrValue = container.attr("data-valmsg-replace"),
58 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
59 |
60 | container.removeClass("field-validation-valid").addClass("field-validation-error");
61 | error.data("unobtrusiveContainer", container);
62 |
63 | if (replace) {
64 | container.empty();
65 | error.removeClass("input-validation-error").appendTo(container);
66 | }
67 | else {
68 | error.hide();
69 | }
70 | }
71 |
72 | function onErrors(event, validator) { // 'this' is the form element
73 | var container = $(this).find("[data-valmsg-summary=true]"),
74 | list = container.find("ul");
75 |
76 | if (list && list.length && validator.errorList.length) {
77 | list.empty();
78 | container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
79 |
80 | $.each(validator.errorList, function () {
81 | $(" ").html(this.message).appendTo(list);
82 | });
83 | }
84 | }
85 |
86 | function onSuccess(error) { // 'this' is the form element
87 | var container = error.data("unobtrusiveContainer"),
88 | replaceAttrValue = container.attr("data-valmsg-replace"),
89 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
90 |
91 | if (container) {
92 | container.addClass("field-validation-valid").removeClass("field-validation-error");
93 | error.removeData("unobtrusiveContainer");
94 |
95 | if (replace) {
96 | container.empty();
97 | }
98 | }
99 | }
100 |
101 | function onReset(event) { // 'this' is the form element
102 | var $form = $(this),
103 | key = '__jquery_unobtrusive_validation_form_reset';
104 | if ($form.data(key)) {
105 | return;
106 | }
107 | // Set a flag that indicates we're currently resetting the form.
108 | $form.data(key, true);
109 | try {
110 | $form.data("validator").resetForm();
111 | } finally {
112 | $form.removeData(key);
113 | }
114 |
115 | $form.find(".validation-summary-errors")
116 | .addClass("validation-summary-valid")
117 | .removeClass("validation-summary-errors");
118 | $form.find(".field-validation-error")
119 | .addClass("field-validation-valid")
120 | .removeClass("field-validation-error")
121 | .removeData("unobtrusiveContainer")
122 | .find(">*") // If we were using valmsg-replace, get the underlying error
123 | .removeData("unobtrusiveContainer");
124 | }
125 |
126 | function validationInfo(form) {
127 | var $form = $(form),
128 | result = $form.data(data_validation),
129 | onResetProxy = $.proxy(onReset, form),
130 | defaultOptions = $jQval.unobtrusive.options || {},
131 | execInContext = function (name, args) {
132 | var func = defaultOptions[name];
133 | func && $.isFunction(func) && func.apply(form, args);
134 | }
135 |
136 | if (!result) {
137 | result = {
138 | options: { // options structure passed to jQuery Validate's validate() method
139 | errorClass: defaultOptions.errorClass || "input-validation-error",
140 | errorElement: defaultOptions.errorElement || "span",
141 | errorPlacement: function () {
142 | onError.apply(form, arguments);
143 | execInContext("errorPlacement", arguments);
144 | },
145 | invalidHandler: function () {
146 | onErrors.apply(form, arguments);
147 | execInContext("invalidHandler", arguments);
148 | },
149 | messages: {},
150 | rules: {},
151 | success: function () {
152 | onSuccess.apply(form, arguments);
153 | execInContext("success", arguments);
154 | }
155 | },
156 | attachValidation: function () {
157 | $form
158 | .off("reset." + data_validation, onResetProxy)
159 | .on("reset." + data_validation, onResetProxy)
160 | .validate(this.options);
161 | },
162 | validate: function () { // a validation function that is called by unobtrusive Ajax
163 | $form.validate();
164 | return $form.valid();
165 | }
166 | };
167 | $form.data(data_validation, result);
168 | }
169 |
170 | return result;
171 | }
172 |
173 | $jQval.unobtrusive = {
174 | adapters: [],
175 |
176 | parseElement: function (element, skipAttach) {
177 | ///
178 | /// Parses a single HTML element for unobtrusive validation attributes.
179 | ///
180 | /// The HTML element to be parsed.
181 | /// [Optional] true to skip attaching the
182 | /// validation to the form. If parsing just this single element, you should specify true.
183 | /// If parsing several elements, you should specify false, and manually attach the validation
184 | /// to the form when you are finished. The default is false.
185 | var $element = $(element),
186 | form = $element.parents("form")[0],
187 | valInfo, rules, messages;
188 |
189 | if (!form) { // Cannot do client-side validation without a form
190 | return;
191 | }
192 |
193 | valInfo = validationInfo(form);
194 | valInfo.options.rules[element.name] = rules = {};
195 | valInfo.options.messages[element.name] = messages = {};
196 |
197 | $.each(this.adapters, function () {
198 | var prefix = "data-val-" + this.name,
199 | message = $element.attr(prefix),
200 | paramValues = {};
201 |
202 | if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
203 | prefix += "-";
204 |
205 | $.each(this.params, function () {
206 | paramValues[this] = $element.attr(prefix + this);
207 | });
208 |
209 | this.adapt({
210 | element: element,
211 | form: form,
212 | message: message,
213 | params: paramValues,
214 | rules: rules,
215 | messages: messages
216 | });
217 | }
218 | });
219 |
220 | $.extend(rules, { "__dummy__": true });
221 |
222 | if (!skipAttach) {
223 | valInfo.attachValidation();
224 | }
225 | },
226 |
227 | parse: function (selector) {
228 | ///
229 | /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
230 | /// with the [data-val=true] attribute value and enables validation according to the data-val-*
231 | /// attribute values.
232 | ///
233 | /// Any valid jQuery selector.
234 |
235 | // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
236 | // element with data-val=true
237 | var $selector = $(selector),
238 | $forms = $selector.parents()
239 | .addBack()
240 | .filter("form")
241 | .add($selector.find("form"))
242 | .has("[data-val=true]");
243 |
244 | $selector.find("[data-val=true]").each(function () {
245 | $jQval.unobtrusive.parseElement(this, true);
246 | });
247 |
248 | $forms.each(function () {
249 | var info = validationInfo(this);
250 | if (info) {
251 | info.attachValidation();
252 | }
253 | });
254 | }
255 | };
256 |
257 | adapters = $jQval.unobtrusive.adapters;
258 |
259 | adapters.add = function (adapterName, params, fn) {
260 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.
261 | /// The name of the adapter to be added. This matches the name used
262 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
263 | /// [Optional] An array of parameter names (strings) that will
264 | /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
265 | /// mmmm is the parameter name).
266 | /// The function to call, which adapts the values from the HTML
267 | /// attributes into jQuery Validate rules and/or messages.
268 | ///
269 | if (!fn) { // Called with no params, just a function
270 | fn = params;
271 | params = [];
272 | }
273 | this.push({ name: adapterName, params: params, adapt: fn });
274 | return this;
275 | };
276 |
277 | adapters.addBool = function (adapterName, ruleName) {
278 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
279 | /// the jQuery Validate validation rule has no parameter values.
280 | /// The name of the adapter to be added. This matches the name used
281 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
282 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value
283 | /// of adapterName will be used instead.
284 | ///
285 | return this.add(adapterName, function (options) {
286 | setValidationValues(options, ruleName || adapterName, true);
287 | });
288 | };
289 |
290 | adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
291 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
292 | /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
293 | /// one for min-and-max). The HTML parameters are expected to be named -min and -max.
294 | /// The name of the adapter to be added. This matches the name used
295 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
296 | /// The name of the jQuery Validate rule to be used when you only
297 | /// have a minimum value.
298 | /// The name of the jQuery Validate rule to be used when you only
299 | /// have a maximum value.
300 | /// The name of the jQuery Validate rule to be used when you
301 | /// have both a minimum and maximum value.
302 | /// [Optional] The name of the HTML attribute that
303 | /// contains the minimum value. The default is "min".
304 | /// [Optional] The name of the HTML attribute that
305 | /// contains the maximum value. The default is "max".
306 | ///
307 | return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
308 | var min = options.params.min,
309 | max = options.params.max;
310 |
311 | if (min && max) {
312 | setValidationValues(options, minMaxRuleName, [min, max]);
313 | }
314 | else if (min) {
315 | setValidationValues(options, minRuleName, min);
316 | }
317 | else if (max) {
318 | setValidationValues(options, maxRuleName, max);
319 | }
320 | });
321 | };
322 |
323 | adapters.addSingleVal = function (adapterName, attribute, ruleName) {
324 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
325 | /// the jQuery Validate validation rule has a single value.
326 | /// The name of the adapter to be added. This matches the name used
327 | /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).
328 | /// [Optional] The name of the HTML attribute that contains the value.
329 | /// The default is "val".
330 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value
331 | /// of adapterName will be used instead.
332 | ///
333 | return this.add(adapterName, [attribute || "val"], function (options) {
334 | setValidationValues(options, ruleName || adapterName, options.params[attribute]);
335 | });
336 | };
337 |
338 | $jQval.addMethod("__dummy__", function (value, element, params) {
339 | return true;
340 | });
341 |
342 | $jQval.addMethod("regex", function (value, element, params) {
343 | var match;
344 | if (this.optional(element)) {
345 | return true;
346 | }
347 |
348 | match = new RegExp(params).exec(value);
349 | return (match && (match.index === 0) && (match[0].length === value.length));
350 | });
351 |
352 | $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
353 | var match;
354 | if (nonalphamin) {
355 | match = value.match(/\W/g);
356 | match = match && match.length >= nonalphamin;
357 | }
358 | return match;
359 | });
360 |
361 | if ($jQval.methods.extension) {
362 | adapters.addSingleVal("accept", "mimtype");
363 | adapters.addSingleVal("extension", "extension");
364 | } else {
365 | // for backward compatibility, when the 'extension' validation method does not exist, such as with versions
366 | // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
367 | // validating the extension, and ignore mime-type validations as they are not supported.
368 | adapters.addSingleVal("extension", "extension", "accept");
369 | }
370 |
371 | adapters.addSingleVal("regex", "pattern");
372 | adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
373 | adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
374 | adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
375 | adapters.add("equalto", ["other"], function (options) {
376 | var prefix = getModelPrefix(options.element.name),
377 | other = options.params.other,
378 | fullOtherName = appendModelPrefix(other, prefix),
379 | element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
380 |
381 | setValidationValues(options, "equalTo", element);
382 | });
383 | adapters.add("required", function (options) {
384 | // jQuery Validate equates "required" with "mandatory" for checkbox elements
385 | if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
386 | setValidationValues(options, "required", true);
387 | }
388 | });
389 | adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
390 | var value = {
391 | url: options.params.url,
392 | type: options.params.type || "GET",
393 | data: {}
394 | },
395 | prefix = getModelPrefix(options.element.name);
396 |
397 | $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
398 | var paramName = appendModelPrefix(fieldName, prefix);
399 | value.data[paramName] = function () {
400 | var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
401 | // For checkboxes and radio buttons, only pick up values from checked fields.
402 | if (field.is(":checkbox")) {
403 | return field.filter(":checked").val() || field.filter(":hidden").val() || '';
404 | }
405 | else if (field.is(":radio")) {
406 | return field.filter(":checked").val() || '';
407 | }
408 | return field.val();
409 | };
410 | });
411 |
412 | setValidationValues(options, "remote", value);
413 | });
414 | adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
415 | if (options.params.min) {
416 | setValidationValues(options, "minlength", options.params.min);
417 | }
418 | if (options.params.nonalphamin) {
419 | setValidationValues(options, "nonalphamin", options.params.nonalphamin);
420 | }
421 | if (options.params.regex) {
422 | setValidationValues(options, "regex", options.params.regex);
423 | }
424 | });
425 |
426 | $(function () {
427 | $jQval.unobtrusive.parse(document);
428 | });
429 | }(jQuery));
--------------------------------------------------------------------------------
21 | @foreach (AuthenticationDescription p in loginProviders) { 22 | 23 | } 24 |
25 |