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