Blazor OIDC 单点登录授权实例5 – 独立SSR App (net8 webapp ) 端授权

  • Blazor OIDC 单点登录授权实例5 – 独立SSR App (net8 webapp ) 端授权已关闭评论
  • 82 次浏览
  • A+
所属分类:.NET技术
摘要

目录:(目录暂时不更新,跟随合集标题往下走)BlazorSSRAppOIDC单点登录(SSO)简化了用户体验,使用户能够在访问多个应用时只需一次登录。这提高了用户满意度,减少了密码遗忘的风险,同时增强了安全性。但是,实现单点登录并不容易,需要应用程序实现和认证服务器的交互逻辑,增加了应用程序的开发工作量。例子中的安全策略中提供了 OpenID Connect (OIDC) 的能力,无需对应用做过多的修改,在十分钟内即可立刻实现单点登录。

目录:

  1. OpenID 与 OAuth2 基础知识
  2. Blazor wasm Google 登录
  3. Blazor wasm Gitee 码云登录
  4. Blazor OIDC 单点登录授权实例1-建立和配置IDS身份验证服务
  5. Blazor OIDC 单点登录授权实例2-登录信息组件wasm
  6. Blazor OIDC 单点登录授权实例3-服务端管理组件
  7. Blazor OIDC 单点登录授权实例4 - 部署服务端/独立WASM端授权
  8. Blazor OIDC 单点登录授权实例5 - 独立SSR App (net8 webapp)端授权
  9. Blazor OIDC 单点登录授权实例6 - Winform 端授权
  10. Blazor OIDC 单点登录授权实例7 - Blazor hybird app 端授权

(目录暂时不更新,跟随合集标题往下走)

源码

BlazorSSRAppOIDC

十分钟搞定单点登录

单点登录(SSO)简化了用户体验,使用户能够在访问多个应用时只需一次登录。这提高了用户满意度,减少了密码遗忘的风险,同时增强了安全性。但是,实现单点登录并不容易,需要应用程序实现和认证服务器的交互逻辑,增加了应用程序的开发工作量。例子中的安全策略中提供了 OpenID Connect (OIDC) 的能力,无需对应用做过多的修改,在十分钟内即可立刻实现单点登录。

当采用单点登录之后,用户只需要登录一次,就可以访问多个应用系统。SSO 通常由一个独立的身份管理系统来完成,该系统为每个用户分配一个全局唯一的标识,用户在登录时,只需要提供一次身份认证,就可以访问所有的应用系统。我们在使用一些网站时,经常会看到“使用微信登录”、“使用 Google 账户登录”等按钮,这些网站就是通过 SSO 来实现的。

采用单点登录有以下几个好处:

用户只需要登录一次,就可以访问多个应用系统,不需要为每个应用系统都单独登录。
应用系统不需要自己实现用户认证,只需将认证工作交给单点登录系统,可以大大减少应用系统的开发工作量。

使用 OIDC 单点登录, 可以简化客户端编写流程, 专注于功能实现而不用重复撰写登录部分功能代码, 也不用直接接触身份验证数据库, 剥离繁琐的重复劳动部分.

建立 net8 webapp ssr 工程

Blazor OIDC 单点登录授权实例5 - 独立SSR App (net8 webapp ) 端授权

引用以下库

    <ItemGroup>         <PackageReference Include="BootstrapBlazor" Version="8.*" />         <PackageReference Include="Densen.Extensions.BootstrapBlazor" Version="8.*" />         <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.*" />         <PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.*" />         <PackageReference Include="Microsoft.Extensions.Http" Version="8.*" />     </ItemGroup> 

_Imports.razor 加入引用

@using BootstrapBlazor.Components @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization 

App.razor 加入必须的UI库引用代码

完整文件

<!DOCTYPE html> <html lang="en">  <head>     <meta charset="utf-8" />     <meta name="viewport" content="width=device-width, initial-scale=1.0" />     <base href="/" />     <Link Href="_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css" />     <Link Href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" />     <Link Href="_content/BootstrapBlazor/css/motronic.min.css" />     <link rel="stylesheet" href="app.css" />     <link rel="stylesheet" href="BlazorSSRAppOIDC.styles.css" />     <HeadOutlet @rendermode="new InteractiveServerRenderMode(false)" /> </head>  <body>     <Routes @rendermode="new InteractiveServerRenderMode(false)" />     <ReconnectorOutlet ReconnectInterval="5000" @rendermode="new InteractiveServerRenderMode(false)" />     <Script Src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></Script>     <script src="_framework/blazor.web.js"></script> </body>  </html> 

Routes.razor 加入授权

完整代码

<Router AppAssembly="typeof(Program).Assembly">     <Found Context="routeData">         <AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)">             <NotAuthorized>                 <p role="alert">您无权访问该资源.</p>             </NotAuthorized>             <Authorizing>                 <p>正在验证您的身份...</p>             </Authorizing>         </AuthorizeRouteView>     </Found> </Router> 

添加Oidc授权配置

Blazor OIDC 单点登录授权实例5 - 独立SSR App (net8 webapp ) 端授权

新建 OidcProfile.cs 文件

using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using System.Security.Claims;  namespace OidcClientShared;  public class OidcProfile {       public static void OidcDIY(OpenIdConnectOptions options)     {         var authority = "https://ids2.app1.es/"; //由于时间的关系,已经部署有一个实际站点, 大家也可以参考往期文章使用本机服务器测试         //authority = "https://localhost:5001/";          var clientId = "Blazor5002";         var callbackEndPoint = "http://localhost:5002";          options.Authority = authority;         options.ClientId = clientId;         options.ResponseType = OpenIdConnectResponseType.Code;         options.ResponseMode = OpenIdConnectResponseMode.Query;          options.SignedOutRedirectUri = callbackEndPoint;         options.CallbackPath = "/authentication/login-callback";         options.SignedOutCallbackPath = "/authentication/logout-callback";         options.Scope.Add("BlazorWasmIdentity.ServerAPI openid profile");          options.GetClaimsFromUserInfoEndpoint = true;         options.SaveTokens = true;         options.MapInboundClaims = false;         options.ClaimActions.MapAll();         options.ClaimActions.MapJsonKey(ClaimTypes.Name, "name");         options.ClaimActions.MapJsonKey(ClaimValueTypes.Email, "email", ClaimValueTypes.Email);         options.ClaimActions.MapJsonKey(ClaimTypes.Role, "role");          options.Events = new OpenIdConnectEvents         {             OnAccessDenied = context =>             {                 context.HandleResponse();                 context.Response.Redirect("/");                 return Task.CompletedTask;             },              OnTokenValidated = context =>             {                 var token = context.TokenEndpointResponse?.AccessToken;                 if (!string.IsNullOrEmpty(token))                 {                     if (context.Principal?.Identity != null)                     {                         var identity = context.Principal!.Identity as ClaimsIdentity;                         identity!.AddClaim(new Claim("AccessToken", token));                      }                  }                  return Task.CompletedTask;             }          };      }  } 

Program.cs 加入授权相关

其中要加入Razor的cshtml支持, 因为登录要依靠管道跳转. 上下有两行都注释在文件内了.

完整代码

using BlazorSSRAppOIDC.Components; using OidcClientShared;  var builder = WebApplication.CreateBuilder(args);  //在具有 Blazor Web 应用程序模板的 .NET 8 中,需要将其更改为, 由于该Pages文件夹已移至该Components文件夹中,因此您需要指定新位置的根目录,或将该Pages文件夹移回项目的根级别 builder.Services.AddRazorPages().WithRazorPagesRoot("/Components/Pages"); // Add services to the container. builder.Services.AddRazorComponents()     .AddInteractiveServerComponents();  builder.Services.AddCascadingAuthenticationState(); builder.Services.AddHttpClient(); builder.Services.AddDensenExtensions(); builder.Services.ConfigureJsonLocalizationOptions(op => {     // 忽略文化信息丢失日志     op.IgnoreLocalizerMissing = true;  });  builder.Services     .AddAuthentication(options =>     {         options.DefaultScheme = "Cookies";         options.DefaultChallengeScheme = "oidc";     })     .AddCookie("Cookies")     .AddOpenIdConnect("oidc", OidcProfile.OidcDIY);   var app = builder.Build();  // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) {     app.UseExceptionHandler("/Error", createScopeForErrors: true);     // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.     app.UseHsts(); }  app.UseHttpsRedirection();  app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseAntiforgery(); //但出于某种原因,这还不够。在 Blazor Web 应用程序模板中,您明确需要调用 app.MapRazorPages();  app.MapRazorComponents<App>()     .AddInteractiveServerRenderMode();  app.Run(); 

Pages 文件夹新建登录Razor页实现登录和注销跳转

Blazor OIDC 单点登录授权实例5 - 独立SSR App (net8 webapp ) 端授权

展开 Login.cshtml 文件组合三角箭头, 编辑 Login.cshtml.cs

Blazor OIDC 单点登录授权实例5 - 独立SSR App (net8 webapp ) 端授权

Login.cshtml.cs

using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc.RazorPages;  namespace PersonalToolKit.Server.Components.Pages;  public class LoginModel : PageModel {     public async Task OnGet(string redirectUri)     {         await HttpContext.ChallengeAsync("oidc", new AuthenticationProperties { RedirectUri = redirectUri });     }  } 

Logout.cshtml.cs

using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc.RazorPages;  namespace PersonalToolKit.Server.Components.Pages;  public class LogoutModel : PageModel {     public async Task OnGet(string redirectUri)     {         await HttpContext.SignOutAsync("Cookies");         await HttpContext.SignOutAsync("oidc", new AuthenticationProperties { RedirectUri = redirectUri });     }  } 

Routes.razor 加入授权

完整代码

Home.razor

完整代码

@page "/" @using System.Security.Claims @inject NavigationManager Navigation  <PageTitle>Home</PageTitle>    <AuthorizeView>     <Authorized>          你好, @context.User.Identity?.Name (@context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role)?.Value)                 <Button Text="注销" OnClick="BeginLogOut" />          <br /><br /><br />         <h5>以下是用户的声明</h5><br />          @foreach (var claim in context.User.Claims)         {             <p>@claim.Type: @claim.Value</p>         }       </Authorized>     <NotAuthorized>          <Button Text="登录" OnClick="BeginLogIn" />          <p>默认账号 test@test.com 密码 0</p>      </NotAuthorized>  </AuthorizeView>  @code {     private string LoginUrl = "login?redirectUri=";     private void BeginLogIn()     {         var returnUrl = Uri.EscapeDataString(Navigation.Uri);         Navigation.NavigateTo(LoginUrl + returnUrl, forceLoad: true);     }      private string LogoutUrl = "logout?redirectUri=";     private void BeginLogOut()     {         var returnUrl = Uri.EscapeDataString(Navigation.Uri);         Navigation.NavigateTo(LogoutUrl + returnUrl, forceLoad: true);     }  } 

运行

Blazor OIDC 单点登录授权实例5 - 独立SSR App (net8 webapp ) 端授权