• Blazor wasm Gitee 码云登录
  • Blazor OIDC 单点登录授权实例1-建立和配置IDS身份验证服务
  • Blazor OIDC 单点登录授权实例2-登录信息组件wasm
  • Blazor OIDC 单点登录授权实例3-服务端管理组件
  • Blazor OIDC 单点登录授权实例4 - 部署服务端/独立WASM端授权
  • Blazor OIDC 单点登录授权实例5 - 独立SSR App (net8 webapp)端授权
  • Blazor OIDC 单点登录授权实例6 - Winform 端授权
  • Blazor OIDC 单点登录授权实例7 - Blazor hybird app 端授权
  • (目录暂时不更新,跟随合集标题往下走)

    BlazorSSRAppOIDC

    十分钟搞定单点登录

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

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

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

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

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

    建立 net8 webapp ssr 工程

    引用以下库

        <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">
        <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>
        <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授权配置

    新建 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页实现登录和注销跳转

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

    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);
    

    Maui Blazor 中文社区 QQ群:645660665

    知识共享许可协议

    本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: https://github.com/densen2014 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

    本文来自博客园,作者:周创琳 AlexChow,转载请注明原文链接:https://www.cnblogs.com/densen2014/p/17969501

    AlexChow

    今日头条 | 博客园 | 知乎 | Gitee | GitHub

    ASP.net热门文章

  • 【Dotnet 工具箱】WPF UI - 现代化设计的开源 WPF 框架
  • net core 使用 SqlSugar
  • .NETCore下CI/CD之自动化测试
  • .net core部署到linux可能碰到的问题
  • Abp vNext 自定义 Ef Core 仓储引发异常
  • .NetCore 消息队列的使用
  • .NetCore WebApi——基于JWT的简单身份认证与授权(Swagger)
  • Abp.NHibernate连接PostgreSQl数据库
  • ModelValidator基于元数据的验证
  • .NET MAUI 安卓应用开发初体验
  • ASP.net推荐文章

  • Gradio.NET 支持 .NET 8 简化 Web 应用开发
  • .NET 轻量化定时任务调度 FreeScheduler
  • WPF 模仿前端大佬写一个Hover效果
  • WPF 模拟UWP原生窗口样式——亚克力|云母材质、自定义标题栏样式、原生DWM动画 (附我封装好的类)
  • .NET 音频采集
  • .NET8 Blazor 从入门到精通:(三)类库和表单
  • wpf 如何7步写一个badge控件
  • .NET 高效Nuget管理工具(开源)
  • .NET 8 跨平台高性能边缘采集网关
  • .NET 窗口/屏幕录制
  •