最新要闻
- 【全球速看料】进口游戏版号时隔548天再发放!数量逐年下降
- 天天实时:2022年iPhone 14系列出货量下调 明年越南将加入生产
- 一加11打破安卓不可能!员工自己都不敢相信
- 全球要闻:兔年邮票“蓝兔子”引争议 真是童年阴影?邮政回应:没人投诉
- 一次多重体验:杰士邦三合一安全套30只19.9元发车
- 【全球报资讯】基于NT架构脱胎换骨!QQ for Linux 3.0正式版上架官网
- 环球实时:卡梅隆自曝《阿凡达2》10分钟删减镜头:动作暴力元素相关
- 每日焦点!老外评选2022年10款最佳RPG游戏:老头环等上榜
- 无人驾驶可达80km/h:深圳坪山云巴1号线正式通车
- 【全球聚看点】还买啥Zen4 酷睿i7-12700KF到手2149元:12核5GHz游戏神U
- 环球今热点:网友吃火锅被反向抹零多收0.3元 店家:四舍五入系统设定
- 【天天速看料】首发极具颠覆性技术 比亚迪仰望发布定档:明年1月5日见
- 全球短讯!根治安卓卡顿的旗舰来了!网友做梦梦到一加11:现在就想买 等不及了
- 世界微速讯:苹果高端制造离不开中国 iPhone 15 Pro Max新增立讯代工:富士康不再是唯一
- 天天快看点丨郑州200多车相撞事故已致1死 大雾是元凶:雾天行车指南要收好
- 大牌现货:超亚N95口罩84.9元30片发车
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
IdentityServer4 - v4.x .Net中的实践应用
认证授权服务的创建
以下内容以密码授权方式为例。
创建模拟访问DB各数据源类
为模拟测试准备的数据源。
/// 假设的用户模型public class TestUser{ public string id { get; set; } = string.Empty; public string username { get; set; } = string.Empty; public string password { get; set; } = string.Empty; public string nickname { get; set; } = string.Empty; public string gender { get; set; } = string.Empty; public string email { get; set; } = string.Empty; public string phone { get; set; } = string.Empty; public string address { get; set; } = string.Empty;}/// 假设的DB数据public class DB{/// Scope数据源方法(4.x 时 很重要!!!)public static IEnumerable ApiScopes => new ApiScope[]{new ApiScope("add","新增"),new ApiScope("search","查询"),new ApiScope("shopping","购物"),}; /// ApiResource 数据源方法/// 需要被认证授权的资源(服务站点)数据源public static IEnumerable GetApiResources => new ApiResource[]{ new ApiResource("user", "会员服务") { // v4.x 时 很重要!!! Scopes = { "add", "search" }, // 指定资源中,可取得的身份(用户)信息 UserClaims={ JwtClaimTypes.NickName } }, new ApiResource("product", "产品服务") { Scopes = { "add", "shopping" }, UserClaims = { JwtClaimTypes.Name, JwtClaimTypes.NickName, "email", "depart", "role"} }, new ApiResource("order", "订单服务") { Scopes = { "add", "shopping"}, UserClaims = { JwtClaimTypes.Gender, "zip" } }};/// 身份资源配置数据源方法public static IEnumerable IdentityResources => new IdentityResource[]{// 必须项new IdentityResources.OpenId(),new IdentityResources.Profile(),// 扩展项new IdentityResources.Email(),new IdentityResources.Phone(),new IdentityResources.Address(),// 自定义追加项new IdentityResource("org",new string[]{"depart","role"}),new IdentityResource("zip",new string[]{"zip"})};/// 客户端数据源方法public static IEnumerable Clients => new Client[]{ new Client { ClientId = "Cli-c", ClientName="客户端-C-密码方式认证", AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, ClientSecrets = { new Secret("secret_code".Sha256()) }, // 支持token过期后自动刷新token,增强体验 AllowOfflineAccess = true, AccessTokenLifetime = 360000, AllowedScopes = { "add", "search", "shopping", IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, JwtClaimTypes.Email, "org","zip", IdentityServerConstants.StandardScopes.OfflineAccess } }};/// 用户数据源方法public static IEnumerable Users => new TestUser[] { new TestUser{ id = "10001", username = "sol", password = "123", nickname = "Sol", email = "sol@domain.com", phone="13888888888", gender = "男", address="jingan" }, new TestUser{ id = "10002", username = "song", password = "123", nickname = "Song", email = "song@domain.com", phone="13888888888", gender = "女", address="jingan" }};/// 用户是否激活方法public static bool GetUserActive(string userid){ return Users.Any(a => a.id == userid);}}
为 Client 实现 IClientStore 接口
/// 客户端数据查询public class ClientStore : IClientStore{ // 客户端验证方法public Task FindClientByIdAsync(string clientId){// 数据库查询 Client 信息var client = DB.Clients.FirstOrDefault(c => c.ClientId == clientId) ?? new Client();client.AccessTokenLifetime = 36000;return Task.FromResult(client);}}
为 ApiResource 实现 IResourceStore 接口
从中可以理出 IdentityResource、ApiResource、ApiScope 三者的关系。
(资料图)
/// /// 各个资源数据的查询方法/// 包括:IdentityResource、ApiResource、ApiScope 三项资源/// public class ResourceStore : IResourceStore{ public Task FindApiResourcesByNameAsync(IEnumerable apiResourceNames) { if (apiResourceNames == null) throw new ArgumentNullException(nameof(apiResourceNames)); var result = DB.GetApiResources.Where(r => apiResourceNames.Contains(r.Name)); return Task.FromResult(result); } public Task FindApiResourcesByScopeNameAsync(IEnumerable scopeNames) { if (scopeNames == null) throw new ArgumentNullException(nameof(scopeNames)); var result = DB.GetApiResources.Where(t => t.Scopes.Any(item => scopeNames.Contains(item))); return Task.FromResult(result); } public Task FindApiScopesByNameAsync(IEnumerable scopeNames) { if (scopeNames == null) throw new ArgumentNullException(nameof(scopeNames)); var result = DB.ApiScopes.Where(w => scopeNames.Contains(w.Name)); return Task.FromResult(result); } public Task FindIdentityResourcesByScopeNameAsync(IEnumerable scopeNames) { if (scopeNames == null) throw new ArgumentNullException(nameof(scopeNames)); var result = DB.IdentityResources.Where(w => scopeNames.Contains(w.Name)); return Task.FromResult(result); } public Task GetAllResourcesAsync() { return Task.FromResult(new Resources(DB.IdentityResources, DB.GetApiResources, DB.ApiScopes)); }}
用户信息 Profile 的接口实现
/// /// 认证通过的用户资料信息 的处理,后续公布到Token中/// public class UserProfileService : IProfileService{ public Task GetProfileDataAsync(ProfileDataRequestContext context) { // 把需要公开到Token中的用户claim信息,放到指定的IssuedClaims中,为后续生成 Token 所用 var userid = context.Subject.GetSubjectId(); if (userid != null) { var claims = context.Subject.Claims.ToList(); // 此方法,会依据Client请求的Scope(Claim),过滤Claim后的集合放入到 IssuedClaims 中 context.AddRequestedClaims(claims); // 不按 Client.Scope 的过滤,所有的用户claim全部放入(不推荐) // context.IssuedClaims = claims.ToList(); } return Task.CompletedTask; } public Task IsActiveAsync(IsActiveContext context) { string userid = context.Subject.GetSubjectId(); // 查询 DB,ids4需要知道 用户是否已激活 context.IsActive = DB.GetUserActive(userid); return Task.CompletedTask; }}
密码方式验证用户,实现 IResourceOwnerPasswordValidator 接口
/// /// 密码方式认证过程/// public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator{ /// /// 1、验证 用户是否合法 /// 2、设定 身份基本信息 /// 3、设定 返回给调用者的 Response 结果信息 /// /// /// public Task ValidateAsync(ResourceOwnerPasswordValidationContext context) { try { //验证用户,用户名和密码是否正确 var user = DB.Users.FirstOrDefault(u => u.username == context.UserName && u.password == context.Password); if (user != null) { #region 设置 身份(用户)基本信息 // 身份信息的相关属性,带入到ids4中 var claimList = new List() { // Claim 多(自定义)属性 new Claim(JwtClaimTypes.Name,user.username), new Claim(JwtClaimTypes.NickName,user.nickname), new Claim(JwtClaimTypes.Email,user.email), new Claim(JwtClaimTypes.Gender,user.gender), new Claim(JwtClaimTypes.PhoneNumber,user.phone), new Claim("zip","200000") }; // 追加Claim自定义用户属性 string[] roles = new string[] { "SupperManage", "manage", "admin", "member" }; string[] departs = new string[] { "销售部", "人事部", "总经理办公室" }; foreach (var rolename in roles) { claimList.Add(new Claim(JwtClaimTypes.Role, rolename)); } foreach (var departname in departs) { claimList.Add(new Claim("depart", departname)); } #endregion #region 设置 返回给调用者的Response信息 // 在以下 GrantValidationResult 类中 // 1、通过以上已组装的 ClaimList,再追加上系统必须的Claim项,组装成最终的Claims // 2、用 Claims ==> 创建出 ClaimsIdentity ==> 再创建出 ClaimsPrincipal // 以完成 Response 的 json 结果 返回给 调用者 context.Result = new GrantValidationResult( subject: user.id, claims: claimList, authenticationMethod: "db_pwdmode", // Response 的 json 自定义追加项 customResponse: new Dictionary { { "custom_append_author", "认证授权请求的Response自定义追加效果" }, { "custom_append_discription", "认证授权请求的Response自定义追加效果" } } ); #endregion } else if (user == null) { context.Result = new GrantValidationResult( TokenRequestErrors.InvalidGrant, "用户认证失败,账号或密码不存在;无效的自定义证书。" ); } } catch (Exception ex) { context.Result = new GrantValidationResult() { IsError = true, Error = ex.Message }; } return Task.CompletedTask; }}
认证授权服务配置
public class Program{ public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); #region IdentityServer 的配置 builder.Services.AddIdentityServer() // 支持开发环境的签名证书 .AddDeveloperSigningCredential() // 分别注册各自接口的实现类 .AddResourceStore().AddClientStore().AddResourceOwnerValidator().AddProfileService(); // 可追加的扩展 //.AddExtensionGrantValidator<微信自定义扩展模式>(); #endregion builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseRouting(); #region 使用 ids4 服务 // 它需要在 [路由] 之后,[授权] 之前。 app.UseIdentityServer(); app.UseAuthorization(); #endregion app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.Run(); }}
认证授权服务请求效果
从上图看出:用户密码验证成功、客户端密钥Secret验证成功。
这里重点解释下Scope:
Client参数Scope中包含了: Scope(shopping) + UserClaim(openid+profile+org+email)
数据源DB类 ApiResource 中的产品服务、订单服务都包含了shopping,所以access_token可以访问这两个服务。
数据源DB类 Client、IdentityResource 中已定义了 openid+profile+org+email,所以access_token中包含了此几种用户信息。
认证授权服务 /connect/userinfo 取得的身份信息图例:
上图显示结果:Client.Scope匹配到的 ApiResources.UserClaims 合并的结果
解析Token数据图例:
上图显示:
aud:已授权的(Client.Scope匹配到的)ApiResource服务名称集合(product/order)
name/nickname/email/role/...Claims数据:已授权服务(product/order)UserClaims的合并结果
client_id:申请的客户端标识
nbf/exp:认证授权时间/token过期时间
Token访问授权服务
创建一个API产品服务,配置产品服务
var builder = WebApplication.CreateBuilder(args);builder.Services.AddControllers();#region Authentication 授权认证builder.Services.AddAuthorization();builder.Services.AddAuthentication(options =>{ // 数据格式设定,以 IdentityServer 风格为准 options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; options.DefaultForbidScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; options.DefaultSignInScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; options.DefaultSignOutScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;}).AddIdentityServerAuthentication(options =>{ options.Authority = "http://localhost:5007"; // IdentityServer 授权服务地址 options.RequireHttpsMetadata = false; // 不需要https options.ApiName = "product"; // 当前服务名称(与认证授权服务中 ApiResources 的名称对应)});#endregionbuilder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();var app = builder.Build();if (app.Environment.IsDevelopment()){ app.UseSwagger(); app.UseSwaggerUI();}app.UseRouting();#region IdentityServer4 注册// 放在路由之后,授权之前app.UseAuthentication();app.UseAuthorization();#endregionapp.MapControllers();app.Run();
API服务中设定必须授权的Action:
/// 获取当前身份信息[HttpGet, Authorize(Roles = "SupperManage")]public IEnumerable
取得当前身份(用户)信息效果图:
-
IdentityServer4 - v4.x .Net中的实践应用
IdentityServer4、IClientStore、IResourceStore、IProfileService、IResourceOwnerPasswordValidator在 NET中的
来源: IdentityServer4 - v4.x .Net中的实践应用
全球最新:第一百一十八篇: JavaScript 原型链式继承
【全球速看料】进口游戏版号时隔548天再发放!数量逐年下降
天天实时:2022年iPhone 14系列出货量下调 明年越南将加入生产
一加11打破安卓不可能!员工自己都不敢相信
全球要闻:兔年邮票“蓝兔子”引争议 真是童年阴影?邮政回应:没人投诉
一次多重体验:杰士邦三合一安全套30只19.9元发车
AcWing1169. 糖果
当前快讯:FreeSWITCH使用ODBC
【全球报资讯】基于NT架构脱胎换骨!QQ for Linux 3.0正式版上架官网
环球实时:卡梅隆自曝《阿凡达2》10分钟删减镜头:动作暴力元素相关
每日焦点!老外评选2022年10款最佳RPG游戏:老头环等上榜
无人驾驶可达80km/h:深圳坪山云巴1号线正式通车
【全球聚看点】还买啥Zen4 酷睿i7-12700KF到手2149元:12核5GHz游戏神U
.NET和JavaScript控件丨Infragistics功能简介
环球今热点:网友吃火锅被反向抹零多收0.3元 店家:四舍五入系统设定
【天天速看料】首发极具颠覆性技术 比亚迪仰望发布定档:明年1月5日见
全球短讯!根治安卓卡顿的旗舰来了!网友做梦梦到一加11:现在就想买 等不及了
世界微速讯:苹果高端制造离不开中国 iPhone 15 Pro Max新增立讯代工:富士康不再是唯一
天天快看点丨郑州200多车相撞事故已致1死 大雾是元凶:雾天行车指南要收好
天天报道:隐性等待和显性等待
python中的mysql操作教程及实例
大牌现货:超亚N95口罩84.9元30片发车
全球通讯!封杀半年之后微软“开恩” 俄罗斯网友可以下载Win11了
2022年进口网络游戏审批结果公布:腾讯《宝可梦大集结》等游戏在列
天天观察:世界最大液体镜面望远镜启用 成本仅为玻璃反射镜的1%
快播:NOIP动态规划
每日聚焦:数据结构(Data Structure)的基本思想是增删改查
环球视点!宝塔网站批量迁移
环球速看:首架C919机组人员分享飞行体验:感受很好、令人信任
加绒不加价:361°全革运动鞋99元大促(门店259元)
环球即时看!GTX 1060三朝元老还能被迫营业?
二代骁龙8折叠旗舰!vivo X Fold 2来了:2K轻薄大屏
实时焦点:不下载不让看全文成为历史!工信部新规将禁止网页强制用户下载应用
开发工具与低代码开发平台丨上海道宁联合Grapecity为您提供各类软件开发工具和服务
当云原生网关遇上图数据库,NebulaGraph 的 APISIX 最佳实践
天天看点:LOJ 6041 「雅礼集训 2017 Day7」事情的相似度 题解 (SAM+启发式合并)
当前热讯:WinNTSetup V5.3.0 Bata5 单文件版
一分钟搞定Netty 三大组件,如果搞不定,再看3遍
世界播报:《阿凡达2》差的远!2022国内电影票房前10:第一超40亿
前沿热点:折叠旗舰卖到白菜价!moto razr 2022宣布调价至4999元
美国人钱包年末又迎重击!极端寒潮导致上周电价飙升超6000%
天天时讯:或售70万对刚比亚迪!东风猛士M-Terrain量产实车曝光:凶悍
只有Redmi做到了!米粉没想到2022年2500元的手机都有无线充电
环球热文:隐私计算之多方安全计算(MPC,Secure Multi-Party Computation)
河南郑新黄河大桥因大雾多车相撞:涉及200多辆车
速递!安卓手机不卡顿!一加11内存基因重组技术揭秘:数据抓取量提升16倍
特斯拉股价年内暴跌70% 韩国散户疯狂抄底!背后原因不简单
女生病假期上9天班反欠公司三百多:被扣10天工资
环球速看:曝特斯拉上海工厂将在1月实施减产计划 原因未知
直降120:百度网盘超级会员12个月SVIP 178元大促
今日关注:交叉编译esp8089
【环球新要闻】Python中itertools详解
playgo是什么意思?playgo是什么牌子?
十年之痒是什么意思?十年之痒的婚姻感悟小说有哪些?
【天天聚看点】女子投资100万元 本金4年仅剩1.71万元!基金经理被集体起诉
神价手慢无:OATLY噢麦力燕麦奶1L*2瓶/19.9元抄底
焦点速读:轿车加气站去加气 一开后备厢车被炸报废
诚意碾压苹果官网!京东开启年终优惠:iPhone 14直降900元
用户已破6亿!钉钉7.0版本发布:解决产业链协同问题
室内地坪是什么意思?室内地坪漆用什么颜色?
苏武留胡节不辱是什么意思?苏武的精神品质是什么?
调配奶粉是什么意思?调制奶粉的营养价值有哪些?
亚热带水果有哪些?亚热带水果的生长环境有哪些?
拜托小姐大结局是什么?拜托小姐演员表
东非大裂谷是哪两个板块张裂形成的?东非大裂谷形成的原因是什么?
龙应台的作品有哪些?龙应台最经典的句子
乌龟和老鹰的寓意是什么?乌龟和老鹰告诉我们什么道理?
【世界热闻】Python实验报告(第8章)
全球观速讯丨Java HashMap原理
天天亮点!认证管理(锐捷交换篇)
天天快看:[PHP]用socket写一个简单的WEB服务器
游戏盒子哪个好?2022年游戏盒子排行榜
无线网络受限或者是无连接是什么原因?无线网受限制或无连接怎么办?
网上订火车票如何取票?网上订火车票用什么软件最好?
小米2s和小米2的区别有哪些?小米2s开不了机怎么办?
网通玩电信游戏卡是什么原因?网通玩电信游戏卡怎么办?
849元 墨案电纸书Air发布:24级冷暖光、30天长续航
焦点简讯:亿万富翁芒格:别再抱怨了、现在的生活比过去好了5倍多
天天报道:比亚迪推出“疯狂星期三”活动:奖品够香 附答案!
落差很大 五菱“电动吉姆尼”谍照曝光:像老头乐
全球要闻:Redmi K60系列最香版本!米粉评K60:2499元无敌 把门焊死了
天天速讯:「实操」结合图数据库、图算法、机器学习、GNN 实现一个推荐系统
天天短讯!HTML 常用标签 tag
Python爬虫实战,requests+openpyxl模块,爬取小说数据并保存txt文档(附源码)
关注:面试官问:为啥不建议使用 Select *?请你大声地回答他!!
即时:DAG任务调度系统 Taier 演进之道,探究DataSourceX 模块
【天天速看料】苹果推出跨年优惠 其实一点也没便宜
时讯:株洲卡丁车比赛事故致车手死亡后续 车手俱乐部声讨场地方
全球今日讯!彻底重构安卓内存底层!一加11将全球首发“内存基因重组”技术
天天微资讯!马斯克被曝内部圈子缺乏持不同观点的人:全是马屁精
全球滚动:K60发布后 倪飞发声:努比亚Z50才是旗舰焊门员
世界观点:RTX 4090玩游戏性能过剩 外星人懂了:将推500Hz高刷显示器
苹果股价三连跌创一年多来最低:2022累计蒸发27%
性能仅比3080略强?RTX 4070 Ti售价曝光 7199元你还可能买不到
全球快资讯:6年过去了:一代神卡GTX 1060依然值得入手
天天微头条丨平价神器!新iPad mini曝光:苹果加量不加价、还在密谋折叠屏惊喜
环球快看点丨马斯克赔哭 公司股价腰斩!消息称特斯拉上海工厂又要减产 卖不动国人不敢兴趣?
速看:中国GPU欲弯道超车:国产显卡向AMD、NV发起冲击
【天天新要闻】实现小程序onShow第一次页面加载不执行