前言

API裸奔是绝对不允许滴,之前专门针对这块分享了jwt的解决方案(WebApi接口裸奔有风险);那如果是微服务,又怎么解决呢?每一个服务都加认证授权也可以解决问题,只是显得认证授权这块冗余,重复在搞事情;IT大佬肯定容忍不了,对于微服务架构,统一的认证授权中心那是必须的。

随着.NetCore的发布,IdentityServer4随之而出,是.Net Foundation的成员之一,专门针对.NetCore而出的认证授权框架,当前.Net圈是比较火的啦;再配上微服务认证授权的必要性,我决定以此开始入手进行微服务架构学习分享;

主要的学习分享思路为敲代码为向导,如果遇到相关理论概念,结合代码案例进行解释,不在单独针对理论知识整理相关文章(主要是担心归纳总结不好,让小伙伴疑惑,所以就想着结合应用案例解释比较容易理解)。

正文

IdentityServer4 主要的功能就是认证和授权,其他功能这里先假装不知道;主要目的就是想用其统一保护各个微服务的接口;先来理解一下认证和授权:

  • 授权(Authorization):在用户身份认证通过之后,授予用户访问资源的过程或是用户授予第三系统访问自己资源的过程,资源可能是个人信息、文件、数据、接口等;OAuth2是现在比较火的授权标准,对于授权流程,后续会举例说明;

    在公司,假如小伙伴是领导,在出差或休假的时候,通常会通过口头、邮件、信息等方式将一些工作临时委托给某人处理,比如签字、参会等,这个过程叫做授权,如果没有授权,签字无效,也不能随意参会;

  • 认证(Authentication):用户身份认证,可以将其理解为登录;系统验证身份凭据是否合法,比如用户名/密码、人脸识别等方式;OpenId Connect是目前比较流行的身份认证标准协议,OpenID是一个去中心化的网上身份认证系统,OpenID Connect是在OAuth2基础进行扩展,增加身份认证和相关身份标识信息;

    稍微有点规模的公司,通常都有自己的办公楼,有专门的保安人员,管控非公司人员的进入, 如果是公司人员,刷卡识别即可进入,如果是非公司人员需要登记个人信息确认才能进入,这个过程可以理解为身份认证;只有验证信息之后才能进入公司。

IdentityServer4 已经将OpenID Connect和OAuth 2.0封装实现,开发者开箱即用,无需再重新自己实现细节,但如果有需要,小伙伴可以在IdentitySever4基础进行扩展个性化需求;

在授权过程中,根据应用场景不同,有四种授权模式可以选择,如下:

  1. Authorization Code(授权码):最完整的授权模式,也是相对比较安全的模式,适用于有后台的应用程序,如MVC项目;
  2. Implicit(简化模式):简化授权码模式,适用于无后台的应用程序,如前后端分离项目;
  3. Resource Owner Password Credentials(资源所有者密码):直接通过用户名和密码获得授权,这种适用于高度信任的应用,因为需要输入用户名和密码,安全泄露风险高;
  4. **Client Credentials(客户端模式) **:这是无用户操作模式,适用于机器对机器的对接,没有用户干预的应用,如后台任务调度应用,采集数据应用等;
  5. 混合模式:以上四种的组合。

其他理论先不说了,我们边撸码边聊,这样记忆深刻一点,这里就从最简单的Client Credentials开始:

Client Credentials 客户端授权模式

客户端模式没有用户,就只是单纯的机器对机器的交互,大概的流程如下:

流程简要说明:

  1. 首先客户端带上凭据向授权服务器获取AccessToken,这里的客户端凭据是提前在授权服务器上备案过的;
  2. 授权服务器验证客户端凭据,成功之后直接返回AccessToken;
  3. 客户端在带上AccessToken访问资源服务器;
  4. 资源服务器正常返回结果,如果没有AccessToken是不能访问受保护资源的;

来,结合流程看看代码怎么实现,一步一步来:

>>>先创建API项目---资源服务器
  1. 创建一个OrderController,并在里面新增一个Orders 接口,接口没有进行保护;

  2. 接口没有进行保护,可以任意访问,如下:

>>>再创建认证授权中心项目---授权服务器,将资源服务保护起来

以上的API接口裸奔是有风险的,现在需要统一的认证授权中心进行保护,如下:

  1. 新创建一个API项目,并引入IdentityServer4包,并在内存中模拟相关数据,方便测试;

    术语解释

    ApiScope:就是一个作用域范围,生成的Token只能访问指定范围的资源;

    Client:这里的客户端就是应用,比如MVC项目、纯前端项目、Winfrom/WPF、APP等,必须首先在授权服务器中进行备案并获得授权服务器分配的标识和密码,后续用于获取AccessToken;

  2. 模拟数据准备好了,就在Startup中进行对应的注入和配置,并开启中间件,如下:

  3. 这样就初步完成授权服务器的搭建,这里监听的端口改为6100了,用Postman先来测测是否能正常获取Token,如下:

    可能有新手小伙伴会问,咋知道是这个地址能获取token的? 小伙伴可以在浏览器中输入以下链接,即可看见授权服务器的相关信息(授权服务器地址+/.well-known/openid-configuration):

  4. 授权服务器已经好了,准备将资源服务器接入到授权服务器,对API接口进行保护(ApiDemo项目中),如下:

    注:ApiDemo项目中需要Microsoft.AspNetCore.Authentication.JwtBearer包,因为项目是基于.NetCore3.1的,所以这里引用的包版本为3.1.10。

  5. 然后在接口上面加上[Authorize]特性,将接口保护起来,看运行效果如下:

  6. 在Postman中测试,先获取AccessToken,然后将获取的AccessToken加入到Header中请求资源服务器中受保护的API,如下:

>>>真实客户端访问受保护API---控制台

建一个控制台项目,具体步骤如图:

这里就不用文字说明步骤,小伙伴一边看代码,一边看注释,这样应该比较清晰点:

static async Task Main(string[] args)
{
// 1. 创建一个HttpClient用于请求
var client = new HttpClient();
// 2. 获取授权服务器的相关信息,IdentityModel已经将其封装好了
var disco = await client.GetDiscoveryDocumentAsync("http://localhost:6100");
// 3. 检查是否请求错误
if (disco.IsError)
{
// 错误就打印错误信息,然后直接返回
Console.WriteLine(disco.Error);
return;
}
// 4. 通过授权服务分配的标识,向授权服务器请求AccessToken
var tokenResp = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
// 指定获取token的地址,IdentityModel进行封装,直接使用即可
Address = disco.TokenEndpoint,
// 指定授权服务器分配的客户端标识
ClientId = "client",
// 指定授权服务器分的客户端密码
ClientSecret = "ordersecret"
});
// 5. 检查获取Token是否成功
if (tokenResp.IsError)
{
// 如果失败,打印错误消息并返回
Console.WriteLine(tokenResp.Error);
return;
} // 6. 创建一个请求API资源的HttpClient
var apiClient = new HttpClient();
// 7. 将获取到的Token以Bearer的方案设置在请求头中
apiClient.SetBearerToken(tokenResp.AccessToken);
// 8. 向资源服务器中请求受保护的API
var contentResp = await apiClient.GetAsync("http://localhost:5000/api/Order");
// 9. 打印对应的消息
if (contentResp.IsSuccessStatusCode)
{
var content = await contentResp.Content.ReadAsStringAsync();
Console.WriteLine(JArray.Parse(content));
}
else
{
Console.WriteLine(contentResp.StatusCode);
} Console.ReadLine();
}

到这里离完成还差一步了,什么,资源不是保护了吗,受保护资源也能正常访问了,还差哪一步?

在授权服务器模拟备案客户端的时候,是不是指定了访问资源的作用域,也就是说,备案过的客户端只能访问被授权的API资源,而现在拿到的AccessToken都能访问资源服务器中所有受保护的资源,那是因为资源服务器中的API资源没有限制作用域访问,而在实际项目中,并不是拿到AccessToken就能随便访问,需要做限制,继续往下看↓↓↓

假如指定的scope值和客户端在授权服务器中备案时设置的不一样,就算获取到AccessToken也不能正常访问资源,会报403错误,这里我不截图,小伙伴下去试试。

可能小伙伴会比较急,这都是啥玩意,全是硬编码,垃圾文; 别别别,说好的学习分享嘛,一步一个脚印来嘛,最终肯定是小伙伴想要的,也是我学习的目标;

关于客户端凭据生成的Token,在jwt.io网站解析看看,记录一下,看看后面有用户参与的情况,生成的Token解析出来会有什么不同呢,先上个图(图中解析出来的属性之前在WebApi接口裸奔有风险有说过):

总结

从这篇开始,后续会尽快更新学习分享,小伙伴们加入一起学习,一起讨论。下一篇说说Resource Owner Password Credentials.

一个被程序搞丑的帅小伙,关注"Code综艺圈",跟我一起学~

IdentityServer4 之Client Credentials走起来的更多相关文章

  1. IdentityServer4之Client Credentials(客户端凭据许可)

    IdentityServer4之Client Credentials(客户端凭据许可) 参考 项目创建:0_overview,1_client_credentials 概念:客户端凭据许可 认证服务端 ...

  2. asp.net core IdentityServer4 实现 Client credentials(客户端凭证)

    前言 OAuth 2.0默认四种授权模式(GrantType) 授权码模式(authorization_code) 简化模式(implicit) 密码模式(resource owner passwor ...

  3. IdentityServer4 (1) 客户端授权模式(Client Credentials)

    写在前面 1.源码(.Net Core 2.2) git地址:https://github.com/yizhaoxian/CoreIdentityServer4Demo.git 2.相关章节 2.1. ...

  4. IdentityServer4专题之五:OpenID Connect及其Client Credentials流程模式

    1.基于概念 OAuth2.0与身份认证协议的角色映射 OpenID Connect 这个协议是2014颁发的,基于OAuth2.0,在这个协议中,ID Token会和Access Token一起发回 ...

  5. Identity Server 4 原理和实战(完结)_建立Identity Server 4项目,Client Credentials 授权实例

    创建项目 dotnet new -i IdentityServer4.Templates 多出来的这些模板 adminUI用来测试,想要用再生产环境,需要交钱 结合core的 Identity来使用 ...

  6. [OAuth]基于DotNetOpenAuth实现Client Credentials Grant

    Client Credentials Grant是指直接由Client向Authorization Server请求access token,无需用户(Resource Owner)的授权.比如我们提 ...

  7. 基于 IdentityServer3 实现 OAuth 2.0 授权服务【客户端模式(Client Credentials Grant)】

    github:https://github.com/IdentityServer/IdentityServer3/ documentation:https://identityserver.githu ...

  8. 实现Client Credentials Grant

    [OAuth]基于DotNetOpenAuth实现Client Credentials Grant   Client Credentials Grant是指直接由Client向Authorizatio ...

  9. IdentityServer4:IdentityServer4+API+Client实践OAuth2.0客户端模式(1)

    一.OAuth2.0 1.OAuth2.0概念 OAuth2.0(Open Authorization)是一个开放授权协议:第三方应用不需要接触到用户的账户信息(如用户名密码),通过用户的授权访问用户 ...

随机推荐

  1. PyQt(Python+Qt)学习随笔:怎么在QScrollArea滚动区域中展示子部件的超长内容?

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 滚动区域可以针对部署在其上的子部件在不可见时进行滚动展示,但这种滚动展示仅只能展示内容层可见范围的子 ...

  2. jarvisoj babyphp

    jarvisoj babyphp 涉及知识点: (1)GitHack处理.git源码泄露 (2)php代码注入 解析: 进入题目界面. 看到题目中的用了git那么第一反应肯定是可能存在.git源码泄露 ...

  3. flask中migrate和scipt进行连用

    近期态度消极了,并且还忙着学php,所以可能flask框架的进度不会像之前那么快了.但是还是要保证跟之前高的质量滴.

  4. 当你在浏览器输入一个网址(如http://www.taobao.com),按回车之后发生了什么?

    首先你输入了一个网址并按下了回车,这个时候浏览器会根据这个URL去查找其对应的IP,具体过程如下: 首先是查找浏览器缓存,浏览器会保存一段时间你之前访问过的一些网址的DNS信息,不同浏览器保存的时常不 ...

  5. sklearn决策树应用及可视化

    from sklearn import datasets from sklearn.tree import DecisionTreeClassifier 1.载入iris数据集(from sklear ...

  6. Java并发编程的艺术(八)——锁相关

    锁的作用 控制多个线程访问共享资源. 线程协作 Lock接口 特点 与synchronized类似的同步功能,只是需要显式地获取和释放锁.缺少隐式获取锁的便捷性. 拥有锁获取与释放的可操作性.可中断的 ...

  7. 搭建docker registry私有镜像仓库

    搭建docker registry私有镜像仓库 一.安装docker-distribution yum install -y docker-distribution 安装完成后,启动服务: syste ...

  8. rsync 参数说明及使用参数笔记

    第1章 rsync 命令简介 rsync 是一款开源的.快速的.多功能的.可实现全量及增量的本地或远程数据镜像同步备份的优秀工具. 1.1.1 语法格式 三种模式: 1)本地模式 rsync [选项] ...

  9. Mysql LIMIT的用法

    使用范围 MySQL语句中的limit字句可以帮助我们在使用执行查询的时候,返回数据库中间的数据或者是只提取前几段数据 使用语法 SELECT * FROM table LIMIT [offset,] ...

  10. STL——容器(deque)deque 的插入 insert()

    deque.insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置. 1 #include <iostream> 2 #include <d ...