迎周一,腊月十九,小年倒计时

新年还有两周时间就要到了,学习可不能停,这几天一直在加班调休,周末也如此,不过也是趁着半夜凌晨的时间,继续迁移我的项目到IdentityServer4统一认证授权中心Blog.IdentityServer上,也是基本统一了,目前进度如下:

01、前后端分离全家桶已经完成升级:Blog.Core为api,Blog.Admin为后台管理,Blog.Vue为前台信息展示已经全部搞定,具体的代码查看指定Github的分支即可,分支名基本都是Is4,Ids4等字样;

02、Nuxt.tBug项目目前正在升级中,其实和Vue的前后端分离是一样的,都是使用的同一个组件框架oidc-client,这里就不多说了,如果真的差别大,我就单写一篇文章,否则直接看我的代码就行;

03、ChristDDD MVC项目已经完成迁移,就是今天本文讲解的。

04、WPF项目在进度种,到时候简单写个小Demo就行,我会在我的视频中,给大家讲解,预计春节后出来。

上边共涉及到了我开源的六个项目,三个后端,三个前端,想想这一年也是够可以了,但是在迁移的IdentityServer4中,只用到了常用的两种模式,Implicit和Code模式,其实一般我们web开发,掌握四种就行,除了这两个,还有Hybrid和Client,其他的如果没有精力,可以放一放,那下边我们就快速的说一下如何将MVC项目迁移到Ids4上。这里就简单的说一下操作过程,不会讲解原理,原理我会在视频教程中,详细说到。

Idp项目如何配置

具体的原型图,运行原理,等我视频吧,直接看代码,这里要说一下,如果你是第一次开发学习,我建议尽量使用内存模式,这样会很好的调试,如果直接生成到数据库的话,可能有时候修改了一个配置,还需要重新生成数据库,这个有些浪费时间。

在我们的Config.cs中,新建一个Client,用来应对我们的MVC客户端:

// interactive ASP.NET Core MVC client
new Client
{ClientId = "chrisdddmvc",ClientName="Chris DDD MVC项目",ClientSecrets = { new Secret("secret".Sha256()) },AllowedGrantTypes = GrantTypes.Code,RequireConsent = false,RequirePkce = true,AlwaysIncludeUserClaimsInIdToken=true,//将用户所有的claims包含在IdToken内// 登录回调RedirectUris = { "http://ddd.neters.club/signin-oidc" },// 登出回调地址PostLogoutRedirectUris = { "http://ddd.neters.club/signout-callback-oidc" },// 注意这些scope,一定是上边已经定义好的资源AllowedScopes = new List<string>{IdentityServerConstants.StandardScopes.OpenId,IdentityServerConstants.StandardScopes.Profile,IdentityServerConstants.StandardScopes.Email,"roles","rolename",}
}

这里就强调两点,就是配置一下回调地址,然后就是AlwaysIncludeUserClaimsInIdToken要设置为true,以方便我们后边要从claims声明中获取返回的值。

当然,最后还有一个知识点,就是scope中,如果想要自定义的话,需要先在claims中注册添加,然后在GetIdentityResources中配置:

 // scopes define the resources in your systempublic static IEnumerable<IdentityResource> GetIdentityResources(){return new List<IdentityResource>{new IdentityResources.OpenId(),new IdentityResources.Profile(),new IdentityResources.Email(),new IdentityResource("roles", "角色", new List<string> { JwtClaimTypes.Role }),new IdentityResource("rolename", "角色名", new List<string> { "rolename" }),};}

这里配置就是很简单的,咱们继续看看如何在MVC中配置。

ChristDDD如何配置

如果你之前看过或者用到了我的DDD项目,会发现其实本来是用Identity写的,这次我们迁移到Ids4后,需要做一些变化,具体的直接下载我的Ids4分支就行了,修改的内容比较多。

首先我们把响应的认证服务给抽出来,单独封装,上边的是Ids4的,下边的是普通的Identity的:

然后注入服务:

 // IdentityServer4 注入services.AddId4OidcSetup();

那我们直接看看服务是如何设置的:

  private static readonly string config= "https://ids.neters.club";public static void AddId4OidcSetup(this IServiceCollection services){if (services == null) throw new ArgumentNullException(nameof(services));//关闭默认映射,否则它可能修改从授权服务返回的各种claim属性JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();//添加认证服务,并设置其有关选项services.AddAuthentication(options =>{// 客户端应用设置使用"Cookies"进行认证options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;// identityserver4设置使用"oidc"进行认证options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)// 对使用的OpenIdConnect进行设置,此设置与Identityserver的config.cs中相应client配置一致才可能登录授权成功.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>{options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;options.Authority = config;options.RequireHttpsMetadata = false;//必须https协议options.ClientId = "chrisdddmvc";//idp项目中配置的clientoptions.ClientSecret = "secret";options.SaveTokens = true;options.ResponseType = "code";//响应类型// 下边是所有的scope,必须要和idp项目中一致,至少是一部分options.Scope.Clear();options.Scope.Add("roles");//"roles"options.Scope.Add("rolename");//"roles"options.Scope.Add(OidcConstants.StandardScopes.OpenId);//"openid"options.Scope.Add(OidcConstants.StandardScopes.Profile);//"profile"options.Scope.Add(OidcConstants.StandardScopes.Email);//"email"});}

这里有几个注意事项:ClientId一定要填对,Scope必须是Idp项目中配置的子集,Scope一定要写对,不然的话,会报错,比如我们随便把roles改成roles3:

当然全部粘贴过去就行,其他的都有注释,看看即可。

这里配置也是很简单的,运行到了这里,我们就可以简单的调试了,所有的地址,都可以换成localhost来调试。

没有错误的话,我们就可以正式的跳转登录,登录成功后,跳转回来MVC项目,下面我们就说说如何在MVC客户端项目中,进行策略授权。

MVC客户端做策略授权

上边我们已经登录成功,并也跳回了,那现在就要根据情况,设计授权了,毕竟有些页面是test用户不能访问的,只有超级管理员才能访问的:

首先,在声明策略,然后在控制器配置策略

services.AddAuthorization(options =>{options.AddPolicy("CanWriteStudentData", policy => policy.Requirements.Add(new ClaimRequirement("Students", "Write")));options.AddPolicy("CanRemoveStudentData", policy => policy.Requirements.Add(new ClaimRequirement("Students", "Remove")));options.AddPolicy("CanWriteOrRemoveStudentData", policy => policy.Requirements.Add(new ClaimRequirement("Students", "WriteOrRemove")));});// 这里的策略内容可以任意扩展[HttpGet][Authorize(Policy = "CanWriteStudentData")]public IActionResult Edit(Guid? id){}

接着,我们就来定义授权策略处理器

  public class ClaimsRequirementHandler : AuthorizationHandler<ClaimRequirement>{protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ClaimRequirement requirement){var roleId = context.User.Claims.FirstOrDefault(c => c.Type == "role");var rolename = context.User.Claims.FirstOrDefault(c => c.Type == "rolename");var loginUserName = context.User.Claims.FirstOrDefault(c => c.Type == "preferred_username");if (roleId != null && roleId.Value == "4" && rolename != null && rolename.Value == "SuperAdmin"){context.Succeed(requirement);}return Task.CompletedTask;}}

复杂策略授权如何写,逻辑如何调,上下文中的claims声明如何获取,这里就不多说了,默认已经会了我的第一个项目的Blog.Core的相关内容,这里我们只是来看看是不是能获取到相应的Claims就行:

可以看到我们已经获取到了这个scope,这样我们就可以任意的扩展了。

登录与登出设计

这个其实就很简单了,我们在客户端里,直接登出就行,我写的比较low,当然你可以自己找找例子,我就简单的写了写:

 [Authorize]public IActionResult Login(){return Redirect("index");}public async Task<IActionResult> Logout(){await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);return View("Index");}

登录取了个巧,不写内容,直接加了个Authorize,这样肯定就跳转到登录页了。

然后设计下UI展示 _LoginPartial.cshtml ,注入服务就行:

@inject Christ3D.Domain.Interfaces.IUser SignInManager@if (SignInManager.IsAuthenticated())
{<form asp-area="" asp-controller="Home" asp-action="Logout" method="post" id="logoutForm" class="navbar-right"><ul class="nav navbar-nav navbar-right"><li><a asp-area="" asp-controller="Manage" asp-action="Index" title="Manage">Hello @SignInManager.Name!</a></li><li><button type="submit" class="btn btn-link navbar-btn navbar-link">Log out</button></li></ul></form>
}
else
{<ul class="nav navbar-nav navbar-right"><li><a asp-area="" asp-controller="Home" asp-action="Login">Log in</a></li></ul>
}

最终的展示效果是酱紫的,登出:

登录:

到了这里,我们就已经完成了整体流程了!下边就是部署了。

生产环境部署联调

现在还是两个后端项目,一个是IdentityServer4的部署,很简单的,我目前用的是Nginx部署的,Https安全协议。

客户端是MVC项目,但是用的IIS部署的,因为如何也用Nginx部署的话,客户端向授权中心认证的时候,一直报错,错误是回调地址不匹配,因为nginx部署,显示的地址还是本地的:

但是我在idp项目里,明明配置的是ddd域名:

错误信息是这样的:

但是在IIS中配置,是一切正常的,真的是我学术不精啊,有小伙伴知道的,欢迎给我留言私信拍砖,这里我来个赏金(20大洋),给开源事业做贡献了。

这个时候,PC端已经一切正常了,正当高兴的时候,手机访问,又不行了,这次我很机智,有了上次的JS客户端经验,我直接加了一个Cookie

手机移动端适配

在DDD项目中,新建一个扩展:

 public static class SameSiteHandlingExtensions{public static IServiceCollection AddSameSiteCookiePolicy(this IServiceCollection services){services.Configure<CookiePolicyOptions>(options =>{options.MinimumSameSitePolicy = (SameSiteMode)(-1);options.OnAppendCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);options.OnDeleteCookie = cookieContext => CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);});return services;}private static void CheckSameSite(HttpContext httpContext, CookieOptions options){if (options.SameSite == SameSiteMode.None){var userAgent = httpContext.Request.Headers["User-Agent"].ToString();if (DisallowsSameSiteNone(userAgent)){// For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1)options.SameSite = (SameSiteMode)(-1);}}}private static bool DisallowsSameSiteNone(string userAgent){// Cover all iOS based browsers here. This includes:// - Safari on iOS 12 for iPhone, iPod Touch, iPad// - WkWebview on iOS 12 for iPhone, iPod Touch, iPad// - Chrome on iOS 12 for iPhone, iPod Touch, iPad// All of which are broken by SameSite=None, because they use the iOS networking stackif (userAgent.Contains("CPU iPhone OS 12") || userAgent.Contains("iPad; CPU OS 12")){return true;}// Cover Mac OS X based browsers that use the Mac OS networking stack. This includes:// - Safari on Mac OS X.// This does not include:// - Chrome on Mac OS X// Because they do not use the Mac OS networking stack.if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") && userAgent.Contains("Version/") && userAgent.Contains("Safari")){return true;}// Cover Chrome 50-69, because some versions are broken by SameSite=None, // and none in this range require it.// Note: this covers some pre-Chromium Edge versions, // but pre-Chromium Edge does not require SameSite=None.if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6")){return true;}return false;}}

然后服务配置:

常见的错误

刚刚上边我们已经遇到了两个错误,其实总的来说,都是配置的问题,我会在博客园单写一篇文章,来总结IdentityServer4的所有错误,目前还没有,过一段时间查看就行,现在开发的还比较少。注意这两个错误,然后会调试就行,调试主要在F12,去查看network,看看请求的数据是否异常即可。

到了这里,基本就结束了,还是建议大家多看看官网和官方Demo,真的很有用。

【实战 Ids4】║ 又一个项目迁移完成(MVC)相关推荐

  1. 太恐怖了 两天搞定一个项目 Java Web MVC 网络商城教程+源代码

    两天搞定一个项目 Java Web MVC 网络商城教程+源代码 最近自学做了一个网络商城将以下是代码和教程 环境搭建–数据库设计–页面设计-后台设计 本项目使用的jdk版本是 运行项目前需要先配置好 ...

  2. 【实战 Ids4】║ 控制台密码模式搭配Ocelot网关

    (此岁只能云赏樱了) 书接上文,这些天一直在研究IdentityServer4(下文简称Ids4)框架,发现有很多有意思,或者说比我想象中的知识点,可扩展的多,所以比较开心能钻研进去,就像当时学习AS ...

  3. 废弃fastjson!大型项目迁移Gson保姆级实战

    前言 本篇文章是我这一个多月来帮助组内废弃fastjson框架的总结,我们将大部分Java仓库从fastjson迁移至了Gson. 这么做的主要的原因是公司受够了fastjson频繁的安全漏洞问题,每 ...

  4. 【深度学习图像项目实战-从入门到上线1】怎样学会科学的调研并启动一个项目...

    00 导读 每一个项目的第一步就是立项,立项需要进行充分的调研才能确定是否值得启动一个项目.调研主要要做好两个方向:1,算法调研,它主要是确定可行的技术路线.更具体的说,需要清楚想做的事情是否已经到达 ...

  5. UE4 如何迁移项目的资产到另一个项目

    UE4 如何迁移项目的资产到另一个项目 第一步:鼠标右键需要迁移资产的项目,选择打开 第二步:选择需要迁移的资产,鼠标右键,选择 Asset Actions 菜单,选择 Migrate... 选项 第 ...

  6. Django从理论到实战(part3)--创建一个Django项目

    学习笔记,仅供参考 本系列Blog以应用为主,理论基础部分我在后端专栏的Django系列博客已经写过了,如果有些需要补充的知识点,我会在这个系列中,尽量详细的写一下. 文章目录 创建一个Django项 ...

  7. 怎样学会科学的调研并启动一个项目

    文章首发于微信公众号<有三AI> [深度学习图像项目实战-从入门到上线1]怎样学会科学的调研并启动一个项目 00 导读 每一个项目的第一步就是立项,立项需要进行充分的调研才能确定是否值得启 ...

  8. .NET项目迁移到.NET Core操作指南

    这篇文章,汇集了大量优秀作者写的关于".NET迁移到.NET Core"资料文章以及微软官方教程文档.是我在迁移公司框架项目到.NET Core和.NET Standard时遇到的 ...

  9. 测试开发【Mock平台】04实战:前后端项目初始化与登录鉴权实现

    [Mock平台]为系列测试开发教程,从0到1编码带你一步步使用Spring Boot 和 Antd React 框架完成搭建一个测试工具平台,希望作为一个实战项目能为你的测试开发学习有帮助. 一.后端 ...

最新文章

  1. 去中心化已成大势所趋,手机的中枢地位岌岌可危?
  2. docker--在centos镜像安装mysql
  3. 东南亚下半年做什么产品好?解读Lazadashopee服装类热销及需求品类
  4. 具有WildFly,Arquillian,Jenkins和OpenShift的Java EE 7部署管道
  5. python判断英文字母_python判断字符串中是否含有英文 | 个人学习笔记记录
  6. 中小企业信息化及市场
  7. 信息学奥赛一本通 1016:整型数据类型存储空间大小 | OpenJudge NOI 1.2 01
  8. 最新版Spring Cloud Alibaba微服务架构-Openfeign服务调用篇
  9. LR逻辑斯蒂回归 — 机器学习面试
  10. ipfs c++client
  11. 适配器模式在Mybatis中的妙用
  12. 数据分析训练营还有这些内容(Spark)
  13. fedora 安装google浏览器失败,报错
  14. JAVA的图形性能,慢在哪里之分析
  15. 【线上课程】ISO9001:2015质量管理体系标准解析|高清|16节课时
  16. 使用 HTML、CSS 和 JS 创建在线音乐播放器(含免费完整源码)
  17. 魔兽按键精灵 V2.0(修正1)
  18. 基于threejs,完成一个简单的全景图播放器
  19. 软件 黑苹果盒盖不休眠_怎么解决苹果电脑合盖自动休眠问题?
  20. 选择所在城市html按字母,微信小程序实现根据字母选择城市功能

热门文章

  1. 下拉框控件、列表控件、ComboBox
  2. 周报_2013第03周(2013/01/13-2013/01/19)
  3. 在Windows 7中的Windows Media Player 12中快速预览歌曲
  4. 离开互联网行业_如何使用互联网再也不会离开家
  5. IBM与博世合作打造轻松的工业物联网
  6. Java Socke 探究
  7. Openfire3.10beta版源码在eclipse上部署编译
  8. Python编程系列教程第13讲——隐藏数据和封装
  9. C# 10 新特性 —— Lambda 优化
  10. EF Core 6 简化的数据库上下文注册