1、经过元旦两天的全力整改,终于在这新的一年,完成了我的布道生涯的第一个大步走 —— 那就是客户端(VUE)、服务端(ASP.NET Core API)、授权中心(IdentityServer4)的大融合,不仅有文档也有代码,更重要的是实战。

2、这一大步里边当然也有很多小步骤,知识点就不说了,过去的文章里都有。

3、具体的代码和效果呢,我会在下边给大家先简单的说明一下,今天的目的主要是第一篇,概述下,里边的小知识点或者注意事项,其实主要还是Ids4的内容,我还是会慢慢的在以后的文章或者视频中,给大家讲解的。

4、有人问了我的新年计划,主要是CI/CD这一块,配合Docker和DDD,实现第二个闭环,具体还没有想好,等我通知吧。

那下边我就简单的说说效果吧,大家也可以自行体验一下:

http://vueadmin.neters.club

(支持滑动更新等基本操作,后期增加单点登录)

一、Blog.Admin 客户端

Admin项目,是基于Vue+Ele开发的一套后端权限框架,是我自主研发的,里边主要是用到了动态数据库授权认证,使用JWT的复杂策略授权技术,精确到按钮基本,目前部门数据权限还在设计当中,以后也会附加上,这是内部授权这一块,但是认证想做一个统一认证中心,所以就想到了IdentityServer4了。

Vue项目和其他的SPA项目是一样的,连接IdentityServer4认证中心,主要是通过oidc-client这个插件来处理的,

npm install oidc-client --save

用法其实很简单,我简单说下思路,具体的看我的代码,或者看官网都可以:

 class ApplicationUserManager extends UserManager {
constructor () {
super({
authority: 'http://ids.neters.club',
client_id: 'blogadminjs',
redirect_uri: 'http://vueadmin.neters.club/callback',
response_type: 'id_token token',
scope: 'openid profile roles blog.core.api',
post_logout_redirect_uri: 'http://vueadmin.neters.club'
})
}

这个是核心方法,目的是通过配置,实现用户管理,比如登录,跳转,回调,获取用户信息,令牌token,刷新等等,当然以后可能会配合单点登录做处理。

  methods: {
async refreshUserInfo() {
const user = await applicationUserManager.getUser();
if (user) {
this.user.name = user.profile.name;
this.user.isAuthenticated = true;
} else {
this.user.name = "";
this.user.isAuthenticated = false;
}
}
}

这个是使用上边的UserManager来处理远程获取到的用户数据。

具体的代码我已经放到了Blog.Admin项目的ids4分支下了:

二、Blog.Core 资源服务端

这个项目想必都知道了,不多说什么,其实你的任意一个后端服务项目都可以,只要做个表结构,然后配置Identityserver4的认证即可。

//2.2【认证】、IdentityServer4 认证 (暂时忽略)
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://ids.neters.club";
options.RequireHttpsMetadata = false;
options.ApiName = "blog.core.api";
});

这个就是一个核心的代码,将我们BlogCore的资源服务器认证方式,从JWT改成Ids4认证

修改完认证方式以后,下边就是简单的对其中几个小知识点进行微调了,比如某些Claim声明字段,我用的和Ids4不太一样,所以就简单微调一下,主要的修改内容,我也新建了一个分支,可以自行查看下,修改的地方不多。

三、Blog.Idp 认证授权中心

这个才是整个项目的重头戏,项目的重中之重,不过配置起来也不难,具体的操作和使用,我也在录视频和写文章,其实只要了解这几个知识点,就基本学会了Ids4了:

1、如何引用指定的nuget包;

2、JWT、OpenID、OAuth2、OIDC 四者的关系和内容;

3、常见的四种授权方式:简化、混合、密码、客户端等要明白场景,会用;

4、学会联调;

具体的就不多说了,不是今天的讲解内容。今天主要点一下部署的时候的几个知识点,其他的看我的代码即可,这次是master分支。

// 使用证书,可以直接使用开发证书
builder.AddDeveloperSigningCredential(); // 或者自己配置
.AddDeveloperSigningCredential(true, ConstanceHelper.AppSettings.CredentialFileName)
.AddSigningCredential(new X509Certificate2(Path.Combine(Environment.WebRootPath,
Configuration["Certificates:Path"]),
Configuration["Certificates:Password"]))

证书这个很重要,当然既然是安全,就要好好处理,可以配合的证书,继续搞搞HTTPS安全协议,未来还是很多要处理的。

 new Client {
ClientId = "blogadminjs",
ClientName = "Blog.Admin JavaScript Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true, RedirectUris = { "http://vueadmin.neters.club/callback" },
PostLogoutRedirectUris = { "http://vueadmin.neters.club" },
AllowedCorsOrigins = { "http://vueadmin.neters.club" }, AllowedScopes = {
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"roles",
"blog.core.api"
}
}

这是另一个重点,必须要配置客户端,不仅是数据生成到数据库,更是在授权的时候,起到安全的作用。

最后一个小问题,确定是我自己的问题,就是部署的时候,我本来用的Nginx进行代理,但是配置文件里,却依然是localhost:

这样就导致了一个问题,虽然我的认证中心项目可以正常的跑,我是说服务器生产环境,但是用客户端去登录的时候,会自动跑到locaohost里,毕竟配置文件是这样的。

网上找了很多资料,都是本地教程,部署的都很少,我也是很方,最后我找到了官方的一个在线demo项目,它是正常的,我仔细研究了下代码,代码和我的没啥区别,最后灵机一动,我看了看他们的服务器,是IIS!我赶紧实验了一番,还真的是正常了:

但是这个不科学呀,这个我要承认下,肯定是我学艺不精,Nginx肯定是可行的,但是我没有找到为何去配置,这个时候应该查看官网的,当我继续在寻找的时候,但是正好有一个小伙伴的小伙伴告诉了我,贼简单,这个故事告诉我们,学习知识要从细节着手,不能知其然而不知其所以然。

 var builder = services.AddIdentityServer(options =>     {         options.Events.RaiseErrorEvents = true;         options.Events.RaiseInformationEvents = true;         options.Events.RaiseFailureEvents = true;         options.Events.RaiseSuccessEvents = true;         options.IssuerUri = "http://ids.neters.club";// 就是这里         options.PublicOrigin = "http://ids.neters.club";     })

结果还是正确的,看来还是要多读文档,当然如果实在是绕不过来,也可以先求助。

就这样,元旦一整天就过去了,项目也终于放上去了,当然还有很多要优化的,比如如何在Nginx部署IdentityServer的时候配置HTTPS协议,既然开始了,便只顾风雨兼程了。

四、遇到了问题

1、手机版兼容,登录不跳转

本以为上边的已经完成了,电脑上,也各种测试没问题,就在下班的路上,在手机上试试吧,竟然无效?!无法跳转。真是尴尬

夜里开始研究官方的Demo代码,终于发了这一块,竟然需要处理Cookie策略,直接看代码吧:

   public static class SameSiteHandlingExtensions
{
public static IServiceCollection AddSameSiteCookiePolicy(this IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
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.Unspecified;
}
}
} 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 stack
if (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;
}
}

然后把这个服务注册:

最后中间件配置下Cookie策略:

有一个小伙伴说,只配置Cookie中间件即可,你也可以试试再。

2、无效Token,访问无权限接口,异常

谷歌到了官方的 Issue,大家讨论了很多,随便找了一个:https://github.com/IdentityServer/IdentityServer4/issues/1627

简单来说,主要是因为传递了一个无效的Token来访问我们的资源服务器,导致中间件管道内异常,但是不影响正常使用,配置下,对token做下校验即可,比如这样的:

具体的可以查看我的代码。

五、配置HTTPS

在我的微信公众号文章里:

https://mp.weixin.qq.com/s/GQXah1rq6qEMqcgAfWNkIw

六、下一步 2020

今年开始,一切都是新的,第一个闭环已经完成了,当然还有很多需要优化,比如单点登录,DDD和Blog项目也迁移到Ids4上来,那下一个就开始了 —— CI/CD DevOps 我来了。

https://github.com/anjoy8/Blog.IdentityServer(授权)

https://github.com/anjoy8/Blog.Admin(客户端)

https://github.com/anjoy8/Blog.Core(资源服务器)

从壹开始 [ Ids4实战 ] 之七 ║ 客户端、服务端、授权中心全线打通的更多相关文章

  1. [并发并行]_[线程模型]_[Pthread线程使用模型之三 客户端/服务端模型(Client/Server]

    Pthread线程使用模型之三 客户端/服务端模型(Client/Server) 场景 1.在客户端/服务端模型时,客户端向服务端请求一些数据集的操作. 服务端执行执行操作独立的(多进程或跨网络)– ...

  2. win10操作系统下oracle11g客户端/服务端的下载安装配置卸载总结

    win10操作系统下oracle11g客户端/服务端的下载安装配置卸载总结 一:前提 注意:现在有两种安装的方式 1. oracle11g服务端(64位)+oracle客户端(32位)+plsql(3 ...

  3. java版gRPC实战之三:服务端流

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  4. Socket客户端/服务端简单实例

    1.client端 package demo.socket; import java.io.BufferedReader;import java.io.IOException;import java. ...

  5. FastSocket客户端/服务端通讯示例

    新建控制台项目,命名为Server 添加FastSocket.SocketBase,FastSocket.Server引用   Socket命令服务类: Sodao.FastSocket.Server ...

  6. java.net.SocketException:Software caused connection abort: recv failed 异常分析 +socket客户端&服务端代码

    java.net.SocketException:Software caused connection abort: recv failed 异常分析 分类: 很多的技术 2012-01-04 12: ...

  7. Fresco 源码分析(二) Fresco客户端与服务端交互(3) 前后台打通

    4.2.1.2.4 PipelineDraweeControllerBuilder.obtainController()源码分析 续 上节中我们提到两个核心的步骤 obtainDataSourceSu ...

  8. iOS开发推送--客户端 服务端

    1.推送过程简介 (1)App启动过程中,使用UIApplication::registerForRemoteNotificationTypes函数与苹果的APNS服务器通信,发出注册远程推送的申请. ...

  9. Android应用源码基于安卓的校园二手交易系统客户端+服务端+数据库

    该源码是校园二手交易系统应用带服务端,也是一个基于安卓和javaweb的校园二手交易系统,包括整套安卓客户端.javaweb服务端.mysql数据库,可以进行基本的列表显示帖子.显示帖子详情.用户注册 ...

随机推荐

  1. POJ-2502_Subway

    Subway Time Limit: 1000MS Memory Limit: 65536K Description You have just moved from a quiet Waterloo ...

  2. Python基础:04映射类型

    字典是Python语言中唯一的映射类型.一个字典对象是可变的,它是一个容器类型,能存储任意个数的Python对象.字典中的数据是无序排列的. 映射类型也可被称做哈希表,哈希表的算法是获取键,对键执行一 ...

  3. oracle函数 add_months(d1,n1)

    [功能]:返回在日期d1基础上再加n1个月后新的日期. [参数]:d1,日期型,n1数字型 [返回]:日期

  4. oracle函数 INSTR(C1,C2[,I[,J]])

    [功能]在一个字符串中搜索指定的字符,返回发现指定的字符的位置; [说明]多字节符(汉字.全角符等),按1个字符计算 [参数] C1    被搜索的字符串 C2    希望搜索的字符串 I     搜 ...

  5. 实现菜单底部线条沿着 X 轴的值缩放转换scaleX

    效果: 代码: a{padding: 10px 10px; position: relative;} a:before{content: ''; width: 100%; height: 3px; b ...

  6. uni-app中使用Echarts绘画图表

    enmnm...一般会使用npm下载echarts这个包,但是不知道是我自己的配置问题还是别的原因,一直出不来图线, 于是,把Hello uni-app模板里的那个组件抱过来,然后,成了! 首先, 1 ...

  7. HTML静态网页---标签

    一. 创建HTML: (一) body的属性: bgcolor 页面背景色 background   背景壁纸.图片 text   文字颜色 topmargin   上边距 leftmargin    ...

  8. HDU 6623"Minimal Power of Prime"(数学)

    传送门 •题意 给你一个大于 1 的正整数 n: 它可以分解成不同的质因子的幂的乘积的形式,问这些质因子的幂中,最小的幂是多少. •题解 定义 $ans$ 表示最终答案: ①如果 $ans \ge 5 ...

  9. Python3 dir() 函数

    Python dir() 函数 描述 dir() 函数不带参数时,返回当前范围内的变量.方法和定义的类型列表:带参数时,返回参数的属性.方法列表.如果参数包含方法__dir__(),该方法将被调用.如 ...

  10. js三大框架出现的意义

    解决了原始html,css,js的UI与数据状态之间同步的难题,避免了大量的操作DOM代码. 使用了React,Angular和Vue,我们只需要定义一次 UI 界面,不再需要为每个操作编写特定的 U ...