Blazor SSR/WASM IDS/OIDC 单点登录授权实例1-建立和配置IDS身份验证服务

目录:

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

源码

BlazorOIDC/Server

1. 建立 BlazorOIDC 工程

新建wasm工程 BlazorOIDC

  • 框架: 7.0
  • 身份验证类型: 个人账户
  • ASP.NET Core 托管

2. 添加自定义身份实体类,扩展IDS字段

BlazorOIDC.Server项目

编辑 Models/WebAppIdentityUser.cs 文件

using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations;namespace BlazorOIDC.Server.Models;public class ApplicationUser : IdentityUser
{ /// <summary>/// Full name/// </summary>[Display(Name = "全名")][PersonalData]public string? Name { get; set; }/// <summary>/// Birth Date/// </summary>[Display(Name = "生日")][PersonalData]public DateTime? DOB { get; set; }[Display(Name = "识别码")]public string? UUID { get; set; }[Display(Name = "外联")]public string? provider { get; set; }[Display(Name = "税号")][PersonalData]public string? TaxNumber { get; set; }[Display(Name = "街道地址")][PersonalData]public string? Street { get; set; }[Display(Name = "邮编")][PersonalData]public string? Zip { get; set; }[Display(Name = "县")][PersonalData]public string? County { get; set; }[Display(Name = "城市")][PersonalData]public string? City { get; set; }[Display(Name = "省份")][PersonalData]public string? Province { get; set; }[Display(Name = "国家")][PersonalData]public string? Country { get; set; }[Display(Name = "类型")][PersonalData]public string? UserRole { get; set; }
}

3. 添加自定义声明

BlazorOIDC.Server项目

新建 Data/ApplicationUserClaimsPrincipalFactory.cs 文件

using BlazorOIDC.Server.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System.Security.Claims;namespace Densen.Models.ids;public class ApplicationUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{public ApplicationUserClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> role,IOptions<IdentityOptions> optionsAccessor) : base(userManager, role, optionsAccessor){}protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user){ClaimsIdentity claims = await base.GenerateClaimsAsync(user);var roles = await UserManager.GetRolesAsync(user);foreach (var role in roles){claims.AddClaim(new Claim("roleVIP", role));}return claims;}}

4. 配置文件

BlazorOIDC.Server项目

引用 Microsoft.EntityFrameworkCore.Sqlite 包, 示例使用sqlite数据库演示
引用第三方登录包

Microsoft.AspNetCore.Authentication.Facebook
Microsoft.AspNetCore.Authentication.Google
Microsoft.AspNetCore.Authentication.MicrosoftAccount
Microsoft.AspNetCore.Authentication.Twitter
AspNet.Security.OAuth.GitHub

编辑配置文件 appsettings.json, 添加连接字符串和第三方登录ClientId/ClientSecret等配置

{"ConnectionStrings": {"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-BlazorOIDC.Server-e292861d-0c29-45ea-84b1-b4558d5aa35d;Trusted_Connection=True;MultipleActiveResultSets=true","IdsSQliteConnection": "Data Source=../ids_api.db;"},"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning"}},"IdentityServer": {"Clients": {"BlazorOIDC.Client": {"Profile": "IdentityServerSPA"}}},"AllowedHosts": "*","Authentication": {"Google": {"Instance": "https://accounts.google.com/o/oauth2/v2/auth","ClientId": "ClientId","ClientSecret": "ClientSecret","CallbackPath": "/signin-google"},"Facebook": {"AppId": "AppId","AppSecret": "AppSecret"},"Microsoft": {"ClientId": "ClientId","ClientSecret": "ClientSecret"},"Twitter": {"ConsumerAPIKey": "ConsumerAPIKey","ConsumerSecret": "ConsumerSecret"},"Github": {"ClientID": "ClientID","ClientSecret": "ClientSecret"},"WeChat": {"AppId": "AppId","AppSecret": "AppSecret"},"QQ": {"AppId": "AppId","AppKey": "AppKey"}}
}

5. 配置IDS身份验证服务

BlazorOIDC.Server项目

编辑 Program.cs 文件

using BlazorOIDC.Server.Data;
using BlazorOIDC.Server.Models;
using Densen.Identity.Areas.Identity;
using Densen.Models.ids;
using Duende.IdentityServer;
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;var builder = WebApplication.CreateBuilder(args);// Add services to the container.
//var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
//builder.Services.AddDbContext<ApplicationDbContext>(options =>
//    options.UseSqlServer(connectionString));//EF Sqlite 配置
builder.Services.AddDbContext<ApplicationDbContext>(o => o.UseSqlite(builder.Configuration.GetConnectionString("IdsSQliteConnection")));builder.Services.AddDatabaseDeveloperPageExceptionFilter();//附加自定义用户声明到用户主体
builder.Services.AddScoped<ApplicationUserClaimsPrincipalFactory>();builder.Services.AddDefaultIdentity<ApplicationUser>(o =>
{   // Password settings.o.Password.RequireDigit = false;o.Password.RequireLowercase = false;o.Password.RequireNonAlphanumeric = false;o.Password.RequireUppercase = false;o.Password.RequiredLength = 1;o.Password.RequiredUniqueChars = 1;
}).AddRoles<IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddClaimsPrincipalFactory<ApplicationUserClaimsPrincipalFactory>();builder.Services.AddIdentityServer(options =>
{options.LicenseKey = builder.Configuration["IdentityServerLicenseKey"];options.Events.RaiseErrorEvents = true;options.Events.RaiseInformationEvents = true;options.Events.RaiseFailureEvents = true;options.Events.RaiseSuccessEvents = true;
}).AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>{options.IdentityResources["openid"].UserClaims.Add("roleVIP");// Client localhostvar url2 = "localhost";var spaClient2 = ClientBuilder.SPA("BlazorWasmIdentity.Localhost").WithRedirectUri($"https://{url2}:5001/authentication/login-callback").WithLogoutRedirectUri($"https://{url2}:5001/authentication/logout-callback").WithScopes("openid Profile").Build();spaClient2.AllowOfflineAccess = true;spaClient2.AllowedCorsOrigins = new[]{$"https://{url2}:5001"};options.Clients.Add(spaClient2);//2024-1-23 更新测试端点配置项var spaClientBlazor5002 = ClientBuilder.SPA("Blazor5002").WithScopes("api").Build();spaClientBlazor5002.AllowedCorsOrigins = new[]{$"http://0.0.0.0",$"http://0.0.0.0:5001",$"http://0.0.0.0:5002",$"http://localhost",$"http://localhost:5001",$"http://localhost:5002",$"https://localhost",$"https://localhost:5001",$"https://localhost:5002"};foreach (var item in spaClientBlazor5002.AllowedCorsOrigins){spaClientBlazor5002.RedirectUris.Add($"{item}/authentication/login-callback");spaClientBlazor5002.PostLogoutRedirectUris.Add($"{item}/authentication/logout-callback");}spaClientBlazor5002.AllowOfflineAccess = true;options.Clients.Add(spaClientBlazor5002);});builder.Services.AddAuthentication();var autbuilder = new AuthenticationBuilder(builder.Services);
autbuilder.AddGoogle(o =>
{o.ClientId = builder.Configuration["Authentication:Google:ClientId"] ?? "";o.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"] ?? "";o.ClaimActions.MapJsonKey("urn:google:profile", "link");o.ClaimActions.MapJsonKey("urn:google:image", "picture");
});
//autbuilder.AddFacebook(o =>
//{
//    o.AppId = builder.Configuration["Authentication:Facebook:AppId"] ?? "";
//    o.AppSecret = builder.Configuration["Authentication:Facebook:AppSecret"] ?? "";
//});
//autbuilder.AddTwitter(o =>
//{
//    o.ConsumerKey = builder.Configuration["Authentication:Twitter:ConsumerAPIKey"] ?? "";
//    o.ConsumerSecret = builder.Configuration["Authentication:Twitter:ConsumerSecret"] ?? "";
//    o.RetrieveUserDetails = true;
//});
autbuilder.AddGitHub(o =>
{o.ClientId = builder.Configuration["Authentication:Github:ClientID"] ?? "";o.ClientSecret = builder.Configuration["Authentication:Github:ClientSecret"] ?? "";
});
//autbuilder.AddMicrosoftAccount(o =>
//{
//    o.ClientId = builder.Configuration["Authentication:Microsoft:ClientId"] ?? "";
//    o.ClientSecret = builder.Configuration["Authentication:Microsoft:ClientSecret"] ?? "";
//});
//if (WeChat) autbuilder.AddWeChat(o =>
//{
//    o.AppId = Configuration["Authentication:WeChat:AppId"];
//    o.AppSecret = Configuration["Authentication:WeChat:AppSecret"];
//    o.UseCachedStateDataFormat = true;
//})
//autbuilder.AddQQ(o =>
//{
//    o.AppId = builder.Configuration["Authentication:QQ:AppId"] ?? "";
//    o.AppKey = builder.Configuration["Authentication:QQ:AppKey"] ?? "";
//});
autbuilder.AddOpenIdConnect("oidc", "Demo IdentityServer", options =>
{options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;options.SignOutScheme = IdentityServerConstants.SignoutScheme;options.SaveTokens = true;options.Authority = "https://demo.duendesoftware.com";options.ClientId = "interactive.confidential";options.ClientSecret = "secret";options.ResponseType = "code";options.TokenValidationParameters = new TokenValidationParameters{NameClaimType = "name",RoleClaimType = "role"};
});builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<ApplicationUser>>();var app = builder.Build();// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{app.UseMigrationsEndPoint();app.UseWebAssemblyDebugging();
}
else
{app.UseExceptionHandler("/Error");// 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.UseBlazorFrameworkFiles();
app.UseStaticFiles();app.UseRouting();
app.UseCors(o => o.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());app.UseIdentityServer();
app.UseAuthorization();app.MapBlazorHub();
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");app.Run();

6. 运行工程

因为篇幅的关系,具体数据库改为sqlite生成脚本步骤参考以前文章或者直接拉源码测试

  • 点击注册按钮
  • 用户名 test@test.com
  • 密码 1qaz2wsx

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 点击 Apply Migrations 按钮

  • 刷新页面

  • 已经可以成功登录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/684857.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【实战】一、Jest 前端自动化测试框架基础入门(二) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(二)

文章目录 一、Jest 前端自动化测试框架基础入门5.Jest 中的匹配器toBe 匹配器toEqual匹配器toBeNull匹配器toBeUndefined匹配器和toBeDefined匹配器toBeTruthy匹配器toBeFalsy匹配器数字相关的匹配器字符串相关的匹配器数组相关的匹配器异常情况的匹配器 6.Jest 命令行工具的使…

DSA 经典数据结构与算法 学习心得和知识总结(三) |有向无环图及其应用

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《算法导论》第三版 就是这本被封神的杰作&#xff0c;就是它&#x1f926; 2、参考书籍&#xff1a;《数据结构》严奶奶版 3、参考书…

DataX源码分析-插件机制

系列文章目录 一、DataX详解和架构介绍 二、DataX源码分析 JobContainer 三、DataX源码分析 TaskGroupContainer 四、DataX源码分析 TaskExecutor 五、DataX源码分析 reader 六、DataX源码分析 writer 七、DataX源码分析 Channel 八、DataX源码分析-插件机制 文章目录 系列文章…

基于GPT一键完成数据分析全流程的AI Agent: Streamline Analyst

大型语言模型&#xff08;LLM&#xff09;的兴起不仅为获取知识和解决问题开辟了新的可能性&#xff0c;而且催生了一些新型智能系统&#xff0c;例如旨在辅助用户完成特定任务的AI Copilot以及旨在自动化和自主执行复杂任务的AI Agent&#xff0c;使得编程、创作等任务变得高效…

Prompt Tuning:深度解读一种新的微调范式

阅读该博客&#xff0c;您将系统地掌握如下知识点&#xff1a; 什么是预训练语言模型&#xff1f; 什么是prompt&#xff1f;为什么要引入prompt&#xff1f;相比传统fine-tuning有什么优势&#xff1f; 自20年底开始&#xff0c;prompt的发展历程&#xff0c;哪些经典的代表…

CV | Segment Anything论文详解及代码实现

本文主要是详解解释了SAM的论文部分以及代码实现~ 论文&#xff1a;2023.04.05_Segment Anything 论文地址&#xff1a;2304.02643.pdf (arxiv.org) 代码地址&#xff1a;facebookresearch/segment-anything: The repository provides code for running inference with the Seg…

随机过程及应用学习笔记(四) 马尔可夫过程

马尔可夫过程是理论上和实际应用中都十分重要的一类随机过程。 目录 前言 一、马尔可夫过程的概念 二、离散参数马氏链 1 定义 2 齐次马尔可夫链 3 齐次马尔可夫链的性质 三、齐次马尔可夫链状态的分类 四、有限马尔可夫链 五、状态的周期性 六、极限定理 七、生灭过…

接口测试方法论

第1章 测试那点事 单元测试》接口测试》界面测试 接口就是包含特定输入和特定输出的一套逻辑处理单元&#xff0c;用户无须知晓接口的内部实现逻辑&#xff0c;这也可以称为接口的黑河处理逻辑。因为服务对象不同&#xff0c;接口又可分为两种&#xff1a;一种是系统或服务的…

K8S集群实践之十:虚拟机部署阶段性总结

目录 1. 说明&#xff1a; 2. 安装准备 2.1 每个节点设置双网卡&#xff0c;一卡做网桥&#xff08;外部访问&#xff09;&#xff0c;一卡做NAT&#xff08;集群内网访问&#xff09; 2.2 准备一个可用的代理服务器 3. 由于虚拟机崩溃&#xff08;停电&#xff0c;宿主机…

VBA技术资料MF119:数据验证的添加与删除

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

《苍穹外卖》知识梳理p7-用户下单与模拟微信支付

用户下单与微信支付 一.用户下单 1.1 订单表的设计 订单功能是一个核心的功能&#xff1b; 需要使用2张表&#xff1a; 1.订单表&#xff1a;记录一些订单信息&#xff0c;比如收货人&#xff0c;收获地址&#xff0c;支付金额&#xff0c;下单时间等&#xff1b; 2.订单详情…

GitLab配置SSHKey

段落一&#xff1a;什么是SSH密钥 SSH&#xff08;Secure Shell&#xff09;是一种网络协议&#xff0c;用于安全地远程登录和执行命令。SSH密钥是一种用于身份验证的加密文件&#xff0c;它允许您在与远程服务器通信时&#xff0c;无需输入密码即可进行认证。在GitLab中配置S…

Kibana:如何嵌入 Kibana 仪表板

作者&#xff1a;Carly Richmond 像我这样的前端工程师经常提出的要求是将 Kibana 等来源的现有仪表板嵌入到 JavaScript Web 应用程序中。 这是我必须多次执行的任务&#xff0c;因为我们希望快速部署用户生成的视图或允许用户控制给定的视图。 从我们从精彩的开发者社区收到的…

JVM(3)高级篇

1 GraalVM 1.1 什么是GraalVM GraalVM是Oracle官方推出的一款高性能JDK&#xff0c;使用它享受比OpenJDK或者OracleJDK更好的性能。 GraalVM的官方网址&#xff1a;https://www.graalvm.org/ 官方标语&#xff1a;Build faster, smaller, leaner applications。 更低的CPU、内…

Sora技术报告——Video generation models as world simulators

文章目录 1. 视频生成模型&#xff0c;可以视为一个世界模拟器2. 技术内容2.1 将可视数据转换成patches2.2 视频压缩网络2.3 Spacetime Latent Patches2.4 Scaling transformers 用于视频生成2.5 可变的持续时间&#xff0c;分辨率&#xff0c;宽高比2.6 抽样的灵活性2.7 改进框…

Invalid DataSize: cannot convert ‘30Mb‘ to Long

Invalid DataSize: cannot convert 30Mb to Long servlet:multipart:max-file-size: 30MBmax-request-size: 30MB

【研究生复试】计算机软件工程人工智能研究生复试——资料整理(速记版)——计算机网络

1、JAVA 2、计算机网络 3、计算机体系结构 4、数据库 5、计算机租场原理 6、软件工程 7、大数据 8、英文 自我介绍 2. 计算机网络 1. TCP如何解决丢包和乱序&#xff1f; 序列号&#xff1a;TCP所传送的每段数据都有标有序列号&#xff0c;避免乱序问题发送端确认应答、超时…

反向迭代器------封装的力量

目录 一、list封装中模板参数Ref和Ptr的理解 二、反向迭代器的实现 一、list封装中模板参数Ref和Ptr的理解 对于反向迭代器&#xff0c;是我们在前面STL模拟实现中留下的一个问题。在之前的文章中&#xff0c;我们极大程度上的利用了模板&#xff0c;从而减少了许多的代码&…

09、全文检索 -- Solr -- SpringBoot 整合 Spring Data Solr (生成DAO组件 和 实现自定义查询方法)

目录 SpringBoot 整合 Spring Data SolrSpring Data Solr的功能&#xff08;生成DAO组件&#xff09;&#xff1a;Spring Data Solr大致包括如下几方面功能&#xff1a;Query查询&#xff08;属于半自动&#xff09;代码演示&#xff1a;1、演示通过dao组件来保存文档1、实体类…