From 6acd5f3b7169f1f811e15b20d07fe4307f325dd7 Mon Sep 17 00:00:00 2001 From: bicijinlian Date: Thu, 8 Jun 2023 14:27:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AuthStudy.Authentication.Basic.csproj | 13 ++ AuthStudy.Authentication.Basic/Class1.cs | 7 + .../AuthStudy.Authentication.Browser.csproj | 25 +++ .../BrowserAuthenticationDefault.cs | 14 ++ .../BrowserAuthenticationExtensions.cs | 45 +++++ .../BrowserAuthenticationHandler.cs | 155 ++++++++++++++++++ .../BrowserAuthenticationOptions.cs | 47 ++++++ .../AuthStudy.Authentication.Shared.csproj | 9 + AuthStudy.Authentication.Shared/Class1.cs | 7 + .../AuthStudy.Authentication.SqlServer.csproj | 13 ++ AuthStudy.Authentication.SqlServer/Class1.cs | 7 + .../AuthStudy.Authentication.UrlQuery.csproj | 13 ++ AuthStudy.Authentication.UrlQuery/Class1.cs | 7 + AuthStudy.WebApp/AuthStudy.WebApp.csproj | 26 +++ .../Controllers/AccountsController.cs | 37 +++++ .../Controllers/WeatherForecastController.cs | 33 ++++ AuthStudy.WebApp/Program.cs | 44 +++++ .../Properties/launchSettings.json | 31 ++++ AuthStudy.WebApp/VModels/AccountVM.cs | 11 ++ AuthStudy.WebApp/WeatherForecast.cs | 13 ++ AuthStudy.WebApp/appsettings.Development.json | 8 + AuthStudy.WebApp/appsettings.json | 9 + AuthStudy.sln | 68 ++++++++ 23 files changed, 642 insertions(+) create mode 100644 AuthStudy.Authentication.Basic/AuthStudy.Authentication.Basic.csproj create mode 100644 AuthStudy.Authentication.Basic/Class1.cs create mode 100644 AuthStudy.Authentication.Browser/AuthStudy.Authentication.Browser.csproj create mode 100644 AuthStudy.Authentication.Browser/BrowserAuthenticationDefault.cs create mode 100644 AuthStudy.Authentication.Browser/BrowserAuthenticationExtensions.cs create mode 100644 AuthStudy.Authentication.Browser/BrowserAuthenticationHandler.cs create mode 100644 AuthStudy.Authentication.Browser/BrowserAuthenticationOptions.cs create mode 100644 AuthStudy.Authentication.Shared/AuthStudy.Authentication.Shared.csproj create mode 100644 AuthStudy.Authentication.Shared/Class1.cs create mode 100644 AuthStudy.Authentication.SqlServer/AuthStudy.Authentication.SqlServer.csproj create mode 100644 AuthStudy.Authentication.SqlServer/Class1.cs create mode 100644 AuthStudy.Authentication.UrlQuery/AuthStudy.Authentication.UrlQuery.csproj create mode 100644 AuthStudy.Authentication.UrlQuery/Class1.cs create mode 100644 AuthStudy.WebApp/AuthStudy.WebApp.csproj create mode 100644 AuthStudy.WebApp/Controllers/AccountsController.cs create mode 100644 AuthStudy.WebApp/Controllers/WeatherForecastController.cs create mode 100644 AuthStudy.WebApp/Program.cs create mode 100644 AuthStudy.WebApp/Properties/launchSettings.json create mode 100644 AuthStudy.WebApp/VModels/AccountVM.cs create mode 100644 AuthStudy.WebApp/WeatherForecast.cs create mode 100644 AuthStudy.WebApp/appsettings.Development.json create mode 100644 AuthStudy.WebApp/appsettings.json create mode 100644 AuthStudy.sln diff --git a/AuthStudy.Authentication.Basic/AuthStudy.Authentication.Basic.csproj b/AuthStudy.Authentication.Basic/AuthStudy.Authentication.Basic.csproj new file mode 100644 index 0000000..a636233 --- /dev/null +++ b/AuthStudy.Authentication.Basic/AuthStudy.Authentication.Basic.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/AuthStudy.Authentication.Basic/Class1.cs b/AuthStudy.Authentication.Basic/Class1.cs new file mode 100644 index 0000000..4ad8e6b --- /dev/null +++ b/AuthStudy.Authentication.Basic/Class1.cs @@ -0,0 +1,7 @@ +namespace AuthStudy.Authentication.Basic +{ + public class Class1 + { + + } +} \ No newline at end of file diff --git a/AuthStudy.Authentication.Browser/AuthStudy.Authentication.Browser.csproj b/AuthStudy.Authentication.Browser/AuthStudy.Authentication.Browser.csproj new file mode 100644 index 0000000..70018f1 --- /dev/null +++ b/AuthStudy.Authentication.Browser/AuthStudy.Authentication.Browser.csproj @@ -0,0 +1,25 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + + + + + + + + diff --git a/AuthStudy.Authentication.Browser/BrowserAuthenticationDefault.cs b/AuthStudy.Authentication.Browser/BrowserAuthenticationDefault.cs new file mode 100644 index 0000000..f6e1d59 --- /dev/null +++ b/AuthStudy.Authentication.Browser/BrowserAuthenticationDefault.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AuthStudy.Authentication.Browser +{ + public static class BrowserAuthenticationDefault + { + public const string AuthenticationSchemeName = "BrowserScheme"; + public const string AuthenticationDispayName = "浏览器方案"; + } +} diff --git a/AuthStudy.Authentication.Browser/BrowserAuthenticationExtensions.cs b/AuthStudy.Authentication.Browser/BrowserAuthenticationExtensions.cs new file mode 100644 index 0000000..590e173 --- /dev/null +++ b/AuthStudy.Authentication.Browser/BrowserAuthenticationExtensions.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Microsoft.AspNetCore.Authentication; + +namespace AuthStudy.Authentication.Browser +{ + public static class BrowserAuthenticationExtensions + { + public static AuthenticationBuilder AddBrowser(this AuthenticationBuilder builder) + { + return builder.AddBrowser(BrowserAuthenticationDefault.AuthenticationSchemeName); + } + + + public static AuthenticationBuilder AddBrowser(this AuthenticationBuilder builder, string authenticationScheme) + { + return builder.AddBrowser(authenticationScheme, configureOptions: null); + } + + + public static AuthenticationBuilder AddBrowser(this AuthenticationBuilder builder, Action configureOptions) + { + return builder.AddBrowser(BrowserAuthenticationDefault.AuthenticationSchemeName, configureOptions); + } + + public static AuthenticationBuilder AddBrowser + ( + this AuthenticationBuilder builder, + string authenticationScheme, + Action configureOptions + ) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + return builder; + //return builder.AddScheme>(authenticationScheme, "", configureOptions); + } + } +} diff --git a/AuthStudy.Authentication.Browser/BrowserAuthenticationHandler.cs b/AuthStudy.Authentication.Browser/BrowserAuthenticationHandler.cs new file mode 100644 index 0000000..65957c1 --- /dev/null +++ b/AuthStudy.Authentication.Browser/BrowserAuthenticationHandler.cs @@ -0,0 +1,155 @@ +using System.Security; +using System.Security.Claims; +using System.Security.Policy; +using System.Security.Principal; +using System.Text; +using System.Text.Unicode; +using System.Threading.Tasks.Sources; + +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +using UAParser; + +namespace AuthStudy.Authentication.Browser +{ + /// + /// 浏览器认证 处理器 + /// 可实现子接口 IAuthenticationRequestHandler, 以控制后续中间件是否执行. + /// + public class BrowserAuthenticationHandler : + IAuthenticationHandler, IAuthenticationRequestHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler + where TOptions : AuthenticationSchemeOptions, new() + { + public const string DefaultAuthenticationScheme = BrowserAuthenticationDefault.AuthenticationSchemeName; + + public HttpContext? CurrentHttpContext; + + public List supportedBrowsers = new() { "Chrome", "Edge" }; + + /// + /// 认证 + /// + public Task AuthenticateAsync() + { + var properties = new AuthenticationProperties(); + properties.Items.Add("x-test", "测试"); + + //获取浏览器信息 + CurrentHttpContext?.Request.Headers.TryGetValue("User-Agentx", out StringValues browserInfo); + + ClientInfo clientInfo = Parser.GetDefault().Parse(CurrentHttpContext?.Request.Headers["User-Agent"]); + if (!supportedBrowsers.Contains(clientInfo.UA.Family)) + { + var success = AuthenticateResult.Fail($"不支持的浏览器:{clientInfo.UA.Family}", properties); + + return Task.FromResult(success); + } + + //声明(身份项) + var role = new Claim(ClaimTypes.Role, "Admin"); + var email = new Claim(ClaimTypes.Email, "bicijinlian@168.com"); + + //声明集合 + var Claims = new List(); + Claims.Add(role); + Claims.Add(email); + + //身份:包含声明集合,是声明集合的包装类,一个身份对应多个声明 + var claimsIdentity = new ClaimsIdentity(Claims, DefaultAuthenticationScheme); + + //当事人/主角:是身份Identity的包装,对应多个身份 + var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); + + //票据:对Principal的包装,一对一 + var ticket = new AuthenticationTicket(claimsPrincipal, DefaultAuthenticationScheme); + + //认证结果:认证信息会写入 当前请求的 User属性中,供下一个授权中间件使用 + var result = AuthenticateResult.Success(ticket); + + //调用登陆 + //CurrentHttpContext?.SignInAsync(BrowserAuthentication.DefaultAuthenticationScheme, claimsPrincipal, properties); + + return Task.FromResult(result); + } + + /// + /// 无认证:服务端向客户端(浏览器)发质询(要求提供一个新票据),质询体现为 htpp请求的响应。 + /// + public Task ChallengeAsync(AuthenticationProperties? properties) + { + properties?.Parameters.Add("x-itme", "无效的认证"); + + CurrentHttpContext!.Response.StatusCode = 401; + if (CurrentHttpContext?.Response.Body.CanWrite ?? false) + { + var msg = UTF8Encoding.UTF8.GetBytes("认证无效"); + CurrentHttpContext!.Response.Body.WriteAsync(msg); + } + CurrentHttpContext?.Items.Add("认证结束时间", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + return Task.CompletedTask; + } + + /// + /// 无权限:服务端向客户端(浏览器)发质询(要求提供一个新票据),质询体现为 htpp请求的响应。 + /// + public Task ForbidAsync(AuthenticationProperties? properties) + { + CurrentHttpContext!.Response.StatusCode = 403; + if (CurrentHttpContext?.Response.Body.CanWrite ?? false) + { + var msg = UTF8Encoding.UTF8.GetBytes("无权访问"); + CurrentHttpContext!.Response.Body.WriteAsync(msg); + } + return Task.CompletedTask; + } + + /// + /// IAuthenticationRequestHandler + /// 返回true,立即反回,不执行后续中间件 + /// + /// + public Task HandleRequestAsync() + { + return Task.FromResult(false); + } + + /// + /// 初始化 + /// + public async Task InitializeAsync(AuthenticationScheme scheme, Microsoft.AspNetCore.Http.HttpContext context) + { + //初始化工作,传递给认证方法和授权中间件 + CurrentHttpContext = context; + + context.Items.Add("认证初始时间", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + + await Task.CompletedTask; + } + + /// + /// 登陆方法 + /// 写入Cookie和Session,认证信息持久化等 + /// + public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties? properties) + { + //导航到登陆页 + CurrentHttpContext?.Response.Redirect("https://www.baidu.com"); + + return Task.CompletedTask; + } + + /// + /// 退出方法: 反操作登陆方法 + /// 清除Cookie和Session,删除认证信息的持久化,作废票据等 + /// + public Task SignOutAsync(AuthenticationProperties? properties) + { + //导航到登陆页 + CurrentHttpContext?.Response.Redirect("/api/auth/login"); + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/AuthStudy.Authentication.Browser/BrowserAuthenticationOptions.cs b/AuthStudy.Authentication.Browser/BrowserAuthenticationOptions.cs new file mode 100644 index 0000000..9ec0ca7 --- /dev/null +++ b/AuthStudy.Authentication.Browser/BrowserAuthenticationOptions.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Microsoft.AspNetCore.Authentication; + +namespace AuthStudy.Authentication.Browser +{ + public class BrowserAuthenticationOptions : AuthenticationSchemeOptions + { + /// + /// 是否启用浏览器认证 + /// + public bool Enable { get; set; } = true; + + /// + /// 允许的浏览器 + /// + public List AllowBrowsers { get; set; } = new List(); + + /// + /// 允许移动设备 + /// + public bool AllowMobile { get; set; } = true; + + /// + /// 允许爬虫 + /// + public bool AllowSpider { get; set; } + + public BrowserAuthenticationOptions() : + this(true, new List() { "Chrome", "Firfox", "Edge" }, true, true) + { + + } + + public BrowserAuthenticationOptions(bool enable, List allowedBrowsers, bool allowedMMobile, bool allowedSpider) + { + Enable = enable; + AllowBrowsers = allowedBrowsers; + AllowMobile = allowedMMobile; + AllowSpider = allowedSpider; + } + } +} diff --git a/AuthStudy.Authentication.Shared/AuthStudy.Authentication.Shared.csproj b/AuthStudy.Authentication.Shared/AuthStudy.Authentication.Shared.csproj new file mode 100644 index 0000000..cfadb03 --- /dev/null +++ b/AuthStudy.Authentication.Shared/AuthStudy.Authentication.Shared.csproj @@ -0,0 +1,9 @@ + + + + net7.0 + enable + enable + + + diff --git a/AuthStudy.Authentication.Shared/Class1.cs b/AuthStudy.Authentication.Shared/Class1.cs new file mode 100644 index 0000000..67d46f6 --- /dev/null +++ b/AuthStudy.Authentication.Shared/Class1.cs @@ -0,0 +1,7 @@ +namespace AuthStudy.Authentication.Shared +{ + public class Class1 + { + + } +} \ No newline at end of file diff --git a/AuthStudy.Authentication.SqlServer/AuthStudy.Authentication.SqlServer.csproj b/AuthStudy.Authentication.SqlServer/AuthStudy.Authentication.SqlServer.csproj new file mode 100644 index 0000000..a636233 --- /dev/null +++ b/AuthStudy.Authentication.SqlServer/AuthStudy.Authentication.SqlServer.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/AuthStudy.Authentication.SqlServer/Class1.cs b/AuthStudy.Authentication.SqlServer/Class1.cs new file mode 100644 index 0000000..c8999c5 --- /dev/null +++ b/AuthStudy.Authentication.SqlServer/Class1.cs @@ -0,0 +1,7 @@ +namespace AuthStudy.Authentication.SqlServer +{ + public class Class1 + { + + } +} \ No newline at end of file diff --git a/AuthStudy.Authentication.UrlQuery/AuthStudy.Authentication.UrlQuery.csproj b/AuthStudy.Authentication.UrlQuery/AuthStudy.Authentication.UrlQuery.csproj new file mode 100644 index 0000000..a636233 --- /dev/null +++ b/AuthStudy.Authentication.UrlQuery/AuthStudy.Authentication.UrlQuery.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/AuthStudy.Authentication.UrlQuery/Class1.cs b/AuthStudy.Authentication.UrlQuery/Class1.cs new file mode 100644 index 0000000..4d94851 --- /dev/null +++ b/AuthStudy.Authentication.UrlQuery/Class1.cs @@ -0,0 +1,7 @@ +namespace AuthStudy.Authentication.UrlQuery +{ + public class Class1 + { + + } +} \ No newline at end of file diff --git a/AuthStudy.WebApp/AuthStudy.WebApp.csproj b/AuthStudy.WebApp/AuthStudy.WebApp.csproj new file mode 100644 index 0000000..bd4a9f5 --- /dev/null +++ b/AuthStudy.WebApp/AuthStudy.WebApp.csproj @@ -0,0 +1,26 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + + + + + + + + + diff --git a/AuthStudy.WebApp/Controllers/AccountsController.cs b/AuthStudy.WebApp/Controllers/AccountsController.cs new file mode 100644 index 0000000..3aa401a --- /dev/null +++ b/AuthStudy.WebApp/Controllers/AccountsController.cs @@ -0,0 +1,37 @@ +using AuthStudy.WebApp.VModels; + +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace AuthStudy.WebApp.Controllers +{ + [Route("api/[controller]/[action]")] + [ApiController] + public class AccountsController : ControllerBase + { + public AccountsController() { } + + [Authorize] + [HttpGet] + public IActionResult GetAll() + { + List accounts = new List() + { + new AccountVM(){ Name="张三", Email="zhangsan@qq.com", Password="123456"}, + new AccountVM(){ Name="小明", Email="xiaoming@qq.com", Password="123456"}, + new AccountVM(){ Name="癫子", Email="dianzi@qq.com", Password="123456"} + }; + + return new JsonResult(accounts); + } + + [HttpPost] + public IActionResult Login(string loginName, string loginPassword) + { + var info = new { Name = "", Roles = "Admin" }; + + return new JsonResult(info); + } + } +} diff --git a/AuthStudy.WebApp/Controllers/WeatherForecastController.cs b/AuthStudy.WebApp/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..fde3c5d --- /dev/null +++ b/AuthStudy.WebApp/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace AuthStudy.WebApp.Controllers +{ + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/AuthStudy.WebApp/Program.cs b/AuthStudy.WebApp/Program.cs new file mode 100644 index 0000000..62a1d79 --- /dev/null +++ b/AuthStudy.WebApp/Program.cs @@ -0,0 +1,44 @@ + +using AuthStudy.Authentication.Browser; + +namespace AuthStudy.WebApp +{ + public class Program + { + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + + builder.Services.AddControllers(); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + + #region 认证注册 + builder.Services.AddAuthentication(configOption => + { + configOption.AddScheme>(BrowserAuthenticationDefault.AuthenticationSchemeName, BrowserAuthenticationDefault.AuthenticationDispayName); + }); + #endregion + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + + app.UseAuthentication(); + app.UseAuthorization(); + + + app.MapControllers(); + + app.Run(); + } + } +} \ No newline at end of file diff --git a/AuthStudy.WebApp/Properties/launchSettings.json b/AuthStudy.WebApp/Properties/launchSettings.json new file mode 100644 index 0000000..536f406 --- /dev/null +++ b/AuthStudy.WebApp/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:31387", + "sslPort": 0 + } + }, + "profiles": { + "WebApi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5243", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/AuthStudy.WebApp/VModels/AccountVM.cs b/AuthStudy.WebApp/VModels/AccountVM.cs new file mode 100644 index 0000000..695fb02 --- /dev/null +++ b/AuthStudy.WebApp/VModels/AccountVM.cs @@ -0,0 +1,11 @@ +namespace AuthStudy.WebApp.VModels +{ + public class AccountVM + { + public string Name { get; set; } + + public string Email { get; set; } + + public string Password { get; set; } + } +} diff --git a/AuthStudy.WebApp/WeatherForecast.cs b/AuthStudy.WebApp/WeatherForecast.cs new file mode 100644 index 0000000..9a1ee6e --- /dev/null +++ b/AuthStudy.WebApp/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace AuthStudy.WebApp +{ + public class WeatherForecast + { + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} \ No newline at end of file diff --git a/AuthStudy.WebApp/appsettings.Development.json b/AuthStudy.WebApp/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/AuthStudy.WebApp/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/AuthStudy.WebApp/appsettings.json b/AuthStudy.WebApp/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/AuthStudy.WebApp/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/AuthStudy.sln b/AuthStudy.sln new file mode 100644 index 0000000..f0e0b08 --- /dev/null +++ b/AuthStudy.sln @@ -0,0 +1,68 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33723.286 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthStudy.WebApp", "AuthStudy.WebApp\AuthStudy.WebApp.csproj", "{834A9BDD-4233-43B6-9084-43F236DA49EF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthStudy.Authentication.Browser", "AuthStudy.Authentication.Browser\AuthStudy.Authentication.Browser.csproj", "{6DEFC525-82CD-4749-9246-53E988C14165}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthStudy.Authentication.Basic", "AuthStudy.Authentication.Basic\AuthStudy.Authentication.Basic.csproj", "{6E85B882-364B-44E3-A3D3-A55F184B08EF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthStudy.Authentication.SqlServer", "AuthStudy.Authentication.SqlServer\AuthStudy.Authentication.SqlServer.csproj", "{F320DAFE-F490-4F2B-B2C8-F32E71903304}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthStudy.Authentication.UrlQuery", "AuthStudy.Authentication.UrlQuery\AuthStudy.Authentication.UrlQuery.csproj", "{C9F1FEDE-FEBC-4507-B70B-7A4DC1AD88EB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthStudy.Authentication.Shared", "AuthStudy.Authentication.Shared\AuthStudy.Authentication.Shared.csproj", "{946FECCE-6382-4138-B840-4189B4F7108A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "认证", "认证", "{0F6CCE40-BD73-4103-99A0-8FE31B4CC7E6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "授权", "授权", "{74577ADF-0E82-4798-8D49-AA70DD82528A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{947159C1-414A-4927-A77B-7A37C8A20BDD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {834A9BDD-4233-43B6-9084-43F236DA49EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {834A9BDD-4233-43B6-9084-43F236DA49EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {834A9BDD-4233-43B6-9084-43F236DA49EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {834A9BDD-4233-43B6-9084-43F236DA49EF}.Release|Any CPU.Build.0 = Release|Any CPU + {6DEFC525-82CD-4749-9246-53E988C14165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6DEFC525-82CD-4749-9246-53E988C14165}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DEFC525-82CD-4749-9246-53E988C14165}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6DEFC525-82CD-4749-9246-53E988C14165}.Release|Any CPU.Build.0 = Release|Any CPU + {6E85B882-364B-44E3-A3D3-A55F184B08EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E85B882-364B-44E3-A3D3-A55F184B08EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E85B882-364B-44E3-A3D3-A55F184B08EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E85B882-364B-44E3-A3D3-A55F184B08EF}.Release|Any CPU.Build.0 = Release|Any CPU + {F320DAFE-F490-4F2B-B2C8-F32E71903304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F320DAFE-F490-4F2B-B2C8-F32E71903304}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F320DAFE-F490-4F2B-B2C8-F32E71903304}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F320DAFE-F490-4F2B-B2C8-F32E71903304}.Release|Any CPU.Build.0 = Release|Any CPU + {C9F1FEDE-FEBC-4507-B70B-7A4DC1AD88EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C9F1FEDE-FEBC-4507-B70B-7A4DC1AD88EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C9F1FEDE-FEBC-4507-B70B-7A4DC1AD88EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C9F1FEDE-FEBC-4507-B70B-7A4DC1AD88EB}.Release|Any CPU.Build.0 = Release|Any CPU + {946FECCE-6382-4138-B840-4189B4F7108A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {946FECCE-6382-4138-B840-4189B4F7108A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {946FECCE-6382-4138-B840-4189B4F7108A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {946FECCE-6382-4138-B840-4189B4F7108A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {6DEFC525-82CD-4749-9246-53E988C14165} = {0F6CCE40-BD73-4103-99A0-8FE31B4CC7E6} + {6E85B882-364B-44E3-A3D3-A55F184B08EF} = {0F6CCE40-BD73-4103-99A0-8FE31B4CC7E6} + {F320DAFE-F490-4F2B-B2C8-F32E71903304} = {0F6CCE40-BD73-4103-99A0-8FE31B4CC7E6} + {C9F1FEDE-FEBC-4507-B70B-7A4DC1AD88EB} = {0F6CCE40-BD73-4103-99A0-8FE31B4CC7E6} + {946FECCE-6382-4138-B840-4189B4F7108A} = {0F6CCE40-BD73-4103-99A0-8FE31B4CC7E6} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {93CE07D0-855A-4D3E-B5FF-D9E9D9142536} + EndGlobalSection +EndGlobal