From 4c681ca76f029292e9d7802277766a16bb13a9e5 Mon Sep 17 00:00:00 2001
From: arthuridea w <2337583+arthuridea@users.noreply.github.com>
Date: Tue, 26 Dec 2023 14:58:15 +0800
Subject: [PATCH] feat:add Microsoft AzureAD login support in demo webapp.
---
NetCore.AIGC.sln | 2 +-
docs/docfx.json | 6 +-
docs/toc.yml | 4 +-
.../Pages/Account/SignedOut.cshtml | 2 +
.../Pages/Account/SignedOut.cshtml.cs | 33 +++++++++++
src/LLMServiceHub/Common/BuildInUser.cs | 7 +++
src/LLMServiceHub/LLMServiceHub.csproj | 17 ++++--
src/LLMServiceHub/Pages/Index.cshtml | 11 +++-
src/LLMServiceHub/Pages/Index.cshtml.cs | 58 +++++++++++++------
.../Pages/Shared/_LoginPartial.cshtml | 2 +-
src/LLMServiceHub/Pages/SignOut.cshtml.cs | 10 +++-
src/LLMServiceHub/Startup.cs | 32 +++++++++-
src/LLMServiceHub/appsettings.json | 11 +++-
13 files changed, 158 insertions(+), 37 deletions(-)
create mode 100644 src/LLMServiceHub/Areas/MicrosoftIdentity/Pages/Account/SignedOut.cshtml
create mode 100644 src/LLMServiceHub/Areas/MicrosoftIdentity/Pages/Account/SignedOut.cshtml.cs
diff --git a/NetCore.AIGC.sln b/NetCore.AIGC.sln
index bb4121e..cfdbf46 100644
--- a/NetCore.AIGC.sln
+++ b/NetCore.AIGC.sln
@@ -24,7 +24,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LLMService.Baidu.ErnieVilg"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03.Docs", "03.Docs", "{7E5E6C28-ABB2-4564-AF1B-D9FCC81B8353}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LLMService.OpenAI.ChatGPT", "src\LLMService.OpenAI.ChatGPT\LLMService.OpenAI.ChatGPT.csproj", "{09322116-1405-47CE-BBB5-35E02167905D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LLMService.OpenAI.ChatGPT", "src\LLMService.OpenAI.ChatGPT\LLMService.OpenAI.ChatGPT.csproj", "{09322116-1405-47CE-BBB5-35E02167905D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/docs/docfx.json b/docs/docfx.json
index 8b46e52..100d83e 100644
--- a/docs/docfx.json
+++ b/docs/docfx.json
@@ -27,7 +27,7 @@
]
}
],
- "dest": "dist/api/v0.0.2.0-preview"
+ "dest": "dist/api/v0.0.2.2-preview"
}
],
"build": {
@@ -51,7 +51,7 @@
]
}
],
- "output": "dist/_site/v0.0.2.0-preview",
+ "output": "dist/_site/v0.0.2.2-preview",
"template": [
"default",
"modern",
@@ -62,7 +62,7 @@
"globalMetadata": {
"_appName": "Aeex.LLMService",
"_appTitle": "Aeex.LLMService",
- "_currentVersion": "0.0.2.0-preview",
+ "_currentVersion": "0.0.2.2-preview",
"_enableSearch": true,
"pdf": true
}
diff --git a/docs/toc.yml b/docs/toc.yml
index 0654eeb..d4ffce3 100644
--- a/docs/toc.yml
+++ b/docs/toc.yml
@@ -1,4 +1,4 @@
- name: Docs
href: docs/
-- name: API(v0.0.2.0-preview)
- href: dist/api/v0.0.2.0-preview/
\ No newline at end of file
+- name: API(v0.0.2.2-preview)
+ href: dist/api/v0.0.2.2-preview/
\ No newline at end of file
diff --git a/src/LLMServiceHub/Areas/MicrosoftIdentity/Pages/Account/SignedOut.cshtml b/src/LLMServiceHub/Areas/MicrosoftIdentity/Pages/Account/SignedOut.cshtml
new file mode 100644
index 0000000..495a2e4
--- /dev/null
+++ b/src/LLMServiceHub/Areas/MicrosoftIdentity/Pages/Account/SignedOut.cshtml
@@ -0,0 +1,2 @@
+@page
+@model LLMServiceHub.Areas.MicrosoftIdentity.Pages.Account.SignedOutModel
diff --git a/src/LLMServiceHub/Areas/MicrosoftIdentity/Pages/Account/SignedOut.cshtml.cs b/src/LLMServiceHub/Areas/MicrosoftIdentity/Pages/Account/SignedOut.cshtml.cs
new file mode 100644
index 0000000..ef105df
--- /dev/null
+++ b/src/LLMServiceHub/Areas/MicrosoftIdentity/Pages/Account/SignedOut.cshtml.cs
@@ -0,0 +1,33 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+
+namespace LLMServiceHub.Areas.MicrosoftIdentity.Pages.Account
+{
+ ///
+ /// Model for the SignOut page.
+ ///
+ [AllowAnonymous]
+ public class SignedOutModel : PageModel
+ {
+ ///
+ /// Method handling the HTTP GET method.
+ ///
+ /// A Sign Out page or Home page.
+ public IActionResult OnGet()
+ {
+ if (User?.Identity?.IsAuthenticated ?? false)
+ {
+ //return LocalRedirect("~/");
+ }
+
+ //return Page();
+ var returnUrl = HttpContext.Request.Query["returnUrl"];
+ if(string.IsNullOrEmpty(returnUrl))
+ {
+ returnUrl = "~/";
+ }
+ return LocalRedirect(returnUrl);
+ }
+ }
+}
diff --git a/src/LLMServiceHub/Common/BuildInUser.cs b/src/LLMServiceHub/Common/BuildInUser.cs
index 769d982..5f165a5 100644
--- a/src/LLMServiceHub/Common/BuildInUser.cs
+++ b/src/LLMServiceHub/Common/BuildInUser.cs
@@ -19,5 +19,12 @@ public class BuildInUser
/// The password.
///
public string Password { get; set; }
+ ///
+ /// Gets or sets the display name.
+ ///
+ ///
+ /// The display name.
+ ///
+ public string DisplayName { get; set; }
}
}
diff --git a/src/LLMServiceHub/LLMServiceHub.csproj b/src/LLMServiceHub/LLMServiceHub.csproj
index 89d40fd..b6fea9c 100644
--- a/src/LLMServiceHub/LLMServiceHub.csproj
+++ b/src/LLMServiceHub/LLMServiceHub.csproj
@@ -42,9 +42,13 @@
+
+
+
+
@@ -63,8 +67,14 @@
-
-
+
+
+
+
+
+
+
+
-
+
diff --git a/src/LLMServiceHub/Pages/Index.cshtml b/src/LLMServiceHub/Pages/Index.cshtml
index 9c080b8..9397bd5 100644
--- a/src/LLMServiceHub/Pages/Index.cshtml
+++ b/src/LLMServiceHub/Pages/Index.cshtml
@@ -363,7 +363,16 @@
-
暂不支持第三方登录
+
+
+ 暂不支持第三方登录
+
+
+ MS Sign in
+
+
+
+
@*
diff --git a/src/LLMServiceHub/Pages/Index.cshtml.cs b/src/LLMServiceHub/Pages/Index.cshtml.cs
index 41d8e88..30b0d28 100644
--- a/src/LLMServiceHub/Pages/Index.cshtml.cs
+++ b/src/LLMServiceHub/Pages/Index.cshtml.cs
@@ -1,11 +1,13 @@
using LLMServiceHub.Common;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.IdentityModel.Tokens;
+using Polly;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
@@ -92,7 +94,7 @@ public IndexModel(
///
/// Called when [get].
///
- public void OnGet(string returnUrl = null)
+ public async Task OnGet(string returnUrl = null)
{
if (!string.IsNullOrEmpty(ErrorMessage))
{
@@ -101,6 +103,16 @@ public void OnGet(string returnUrl = null)
returnUrl ??= Url.Content("~/");
+ if(!User.Identity.IsAuthenticated)
+ {
+ var result = await HttpContext.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme);
+ if (result.Succeeded)
+ {
+ await ExecSignIn(AppConsts.DefaultAuthScheme, result.Principal.Identity.Name, true, returnUrl);
+ Redirect(returnUrl);
+ }
+ }
+
ReturnUrl = returnUrl;
}
@@ -121,20 +133,8 @@ public async Task OnPostAsync(string returnUrl = null)
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
- // set authentication cookie
- var claims = new List
- {
- new Claim(ClaimTypes.Name, Input.UserName),
- new Claim(ClaimTypes.Role, "User")
- };
- var authProperties = new AuthenticationProperties
- {
- IsPersistent = Input.RememberMe,// persistance.
- RedirectUri = string.IsNullOrWhiteSpace(returnUrl) ? "/Index" : returnUrl,
- };
- var identity = new ClaimsIdentity(claims, AppConsts.DefaultAuthScheme);
- var principal = new ClaimsPrincipal(identity);
- await HttpContext.SignInAsync(AppConsts.DefaultAuthScheme, principal, authProperties);
+
+ await ExecSignIn(AppConsts.DefaultAuthScheme, result.IdentityName, Input.RememberMe, returnUrl);
return LocalRedirect(returnUrl);
}
else
@@ -148,15 +148,35 @@ public async Task OnPostAsync(string returnUrl = null)
return Page();
}
- private (bool Succeeded, string Message) ValidateUser(string username, string password, bool persist = false)
+ private async Task ExecSignIn(string scheme, string identityUserName, bool rememberme, string returnUrl)
+ {
+ // set authentication cookie
+ var claims = new List
+ {
+ new Claim(ClaimTypes.Name, identityUserName),
+ new Claim(ClaimTypes.Role, "User")
+ };
+ var authProperties = new AuthenticationProperties
+ {
+ IsPersistent = rememberme,// persistance.
+ RedirectUri = string.IsNullOrWhiteSpace(returnUrl) ? "/Index" : returnUrl,
+ };
+ var identity = new ClaimsIdentity(claims, scheme);
+ var principal = new ClaimsPrincipal(identity);
+ await HttpContext.SignInAsync(scheme, principal, authProperties);
+ }
+
+ private (bool Succeeded, string IdentityName, string Message) ValidateUser(string username, string password)
{
- var ret = (Succeeded: false, Message: "用户不存在");
+ var ret = (Succeeded: false, IdentityName: "", Message: "用户不存在");
var validusers = _configuration.GetSection("Users")
.Get>();
- if(validusers.Any(x=> x.UserName== username && x.Password == password))
+ var user = validusers.FirstOrDefault(x => x.UserName == username && x.Password == password);
+ if (user != null)
{
ret.Succeeded = true;
- ret.Message = "Ok";
+ ret.IdentityName = user.DisplayName;
+ ret.Message = "ok";
}
return ret;
}
diff --git a/src/LLMServiceHub/Pages/Shared/_LoginPartial.cshtml b/src/LLMServiceHub/Pages/Shared/_LoginPartial.cshtml
index 7b95b25..8ae0179 100644
--- a/src/LLMServiceHub/Pages/Shared/_LoginPartial.cshtml
+++ b/src/LLMServiceHub/Pages/Shared/_LoginPartial.cshtml
@@ -4,7 +4,7 @@
-
我
+
@(User.Identity.Name)
测试用户
diff --git a/src/LLMServiceHub/Pages/SignOut.cshtml.cs b/src/LLMServiceHub/Pages/SignOut.cshtml.cs
index 95f9602..8109c97 100644
--- a/src/LLMServiceHub/Pages/SignOut.cshtml.cs
+++ b/src/LLMServiceHub/Pages/SignOut.cshtml.cs
@@ -1,6 +1,7 @@
using LLMServiceHub.Common;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
@@ -20,8 +21,13 @@ public async Task OnGetAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/");
// Clear the existing external cookie to ensure a clean login process
- //await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
- await HttpContext.SignOutAsync(AppConsts.DefaultAuthScheme);
+ await HttpContext.SignOutAsync();
+
+ var oauthResult = await HttpContext.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme);
+ if (oauthResult.Succeeded)
+ {
+ return RedirectToAction("SignOut", "Account", new { Area = "MicrosoftIdentity", returnUrl });
+ }
return LocalRedirect(returnUrl);
}
diff --git a/src/LLMServiceHub/Startup.cs b/src/LLMServiceHub/Startup.cs
index 21ab315..3b518dc 100644
--- a/src/LLMServiceHub/Startup.cs
+++ b/src/LLMServiceHub/Startup.cs
@@ -16,6 +16,12 @@
using Serilog;
using Swashbuckle.AspNetCore.SwaggerGen;
using Unchase.Swashbuckle.AspNetCore.Extensions.Extensions;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Authentication.OpenIdConnect;
+using Microsoft.Identity.Web;
+using Microsoft.Identity.Web.UI;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc.Authorization;
namespace LLMServiceHub
{
@@ -57,6 +63,17 @@ public void ConfigureServices(IServiceCollection services)
var appSettings = Configuration.GetSection(nameof(AppSettings)).Get();
services.AddSingleton(appSettings);
+ /***** cookies ***/
+
+ services.Configure(options =>
+ {
+ // This lambda determines whether user consent for non-essential cookies is needed for a given request.
+ options.CheckConsentNeeded = context => true;
+ options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
+ // Handling SameSite cookie according to https://docs.microsoft.com/en-us/aspnet/core/security/samesite?view=aspnetcore-3.1
+ options.HandleSameSiteCookieCompatibility();
+ });
+
// Ensure HttpContext injected. It will be accessed in Chat service.
services.AddHttpContextAccessor();
@@ -77,6 +94,9 @@ public void ConfigureServices(IServiceCollection services)
/********************************************* End Dependency Injection **********************************************/
+ services.AddMvc().AddMicrosoftIdentityUI();
+ //services.AddControllersWithViews().AddMicrosoftIdentityUI();
+
// Add services to the container.
services.AddRazorPages();
@@ -85,7 +105,7 @@ public void ConfigureServices(IServiceCollection services)
// .AddJsonOptions(options => {
// options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
// });
- services.AddMvc();
+ //services.AddMvc();
#region authentication
@@ -113,7 +133,7 @@ public void ConfigureServices(IServiceCollection services)
options.Events.OnRedirectToLogin = context =>
{
- if(context.Request.Path.StartsWithSegments("/api")||
+ if (context.Request.Path.StartsWithSegments("/api") ||
string.Equals(context.HttpContext.Request.Query["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal) ||
string.Equals(context.HttpContext.Request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal))
{
@@ -124,6 +144,8 @@ public void ConfigureServices(IServiceCollection services)
context.Response.Redirect(context.RedirectUri);
return Task.FromResult(0);
};
+
+ //options.ForwardAuthenticate = OpenIdConnectDefaults.AuthenticationScheme;
})
// api use jwt authentication
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
@@ -131,7 +153,11 @@ public void ConfigureServices(IServiceCollection services)
options.Authority = appSettings.IdentityServerBaseUrl;
options.RequireHttpsMetadata = appSettings.RequireHttpsMetadata;
options.Audience = appSettings.OidcApiName;
- });
+ })
+ //.AddMicrosoftIdentityWebApp(options => Configuration.Bind("AzureAd", options));
+ ;
+
+ services.AddMicrosoftIdentityWebAppAuthentication(configuration: Configuration);
services.AddAuthorization(options =>
{
diff --git a/src/LLMServiceHub/appsettings.json b/src/LLMServiceHub/appsettings.json
index 48f757e..1198f89 100644
--- a/src/LLMServiceHub/appsettings.json
+++ b/src/LLMServiceHub/appsettings.json
@@ -17,6 +17,14 @@
"CorsAllowAnyOrigin": true,
"CorsAllowOrigins": []
},
+ "AzureAd": {
+ "Instance": "https://login.microsoftonline.com/",
+ "Domain": "[Enter the domain of your tenant, e.g. contoso.onmicrosoft.com]",
+ "TenantId": "[Enter 'common', or 'organizations' or the Tenant Id (Obtained from the Azure portal. Select 'Endpoints' from the 'App registrations' blade and use the GUID in any of the URLs), e.g. da41245a5-11b3-996c-00a8-4d99re19f292]",
+ "ClientId": "[Enter the Client Id (Application ID obtained from the Azure portal), e.g. ba74781c2-53c2-442a-97c2-3d60re42f403]",
+ "CallbackPath": "/signin-oidc",
+ "SignedOutCallbackPath": "/signout-callback-oidc"
+ },
"BaiduWenxinSettings": {
"ClientId": "",
"ClientSecret": "",
@@ -30,7 +38,8 @@
"Users": [
{
"UserName": "",
- "Password": ""
+ "Password": "",
+ "DisplayName": ""
}
]
}