前言

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. pom文件中<dependencies>和<dependencyManagement>的区别

    在父pom中,如果使用了<dependencies>标签,那么在该标签体中的所有jar包,即使子工程中没有写这些依赖,依旧会引用. 如果使用了<dependencyManagemen ...

  2. 第7.15节 Python中classmethod定义的类方法详解

    第7.15节  Python中classmethod定义的类方法详解 类中的方法,除了实例方法外,还有两种方法,分别是类方法和静态方法.本节介绍类方法的定义和使用. 一.    类方法的定义 在类中定 ...

  3. Python中排序方法sort、函数sorted的key参数的作用分析

    从Python2.4开始,list.sort方法 和 sorted方法 都增加了一个 'key' 参数用来在进行比较之前指定每个列表元素上要调用的函数,将函数的返回值作为比较的依据. 那么怎么使用这个 ...

  4. 第9.4节 Python中用readline读取二进制文件方式打开文件

    在<第9.3节 Python的文件内容读取:readline>中介绍了使用readline读取文件的处理,readline除了使用文本文件方式打开文件读外,也可以读取二进制方式打开的文件, ...

  5. 第二十一章、 Model/View便利类列表部件QListWidget详解

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.概述 列表部件(List Widget)对应类QListWidget,是从QListView派生 ...

  6. 团队作业4-Day1

    团队作业4-Day1 1. 各个成员在 Alpha 阶段认领的任务 Alpha任务分配 人员 小程序样式实现 吴安冬+吴梓华 小程序js代码及云数据实现 庾艺锋+白军强 项目测试 王泽鑫+赵玮锋 2. ...

  7. 基于gin的golang web开发:服务间调用

    微服务开发中服务间调用的主流方式有两种HTTP.RPC,HTTP相对来说比较简单.本文将使用 Resty 包来实现基于HTTP的微服务调用. Resty简介 Resty 是一个简单的HTTP和REST ...

  8. 密码学系列之:明文攻击和Bletchley Park

    目录 简介 crib和明文攻击 布莱奇利公园(Bletchley Park) 简介 明文攻击就是指已经知道了部分明文和它对应的加密后的字段,从而可以推测出使用的加密手段或者密码本.明文攻击这个故事还要 ...

  9. 题解-CF1139D Steps to One

    题面 CF1139D Steps to One 一个数列,每次随机选一个 \([1,m]\) 之间的数加在数列末尾,数列中所有数的 \(\gcd=1\) 时停止,求期望长度 \(\bmod 10^9+ ...

  10. Angular:惰性加载的模块

    ①通过ng new angular-module创建一个全新的angular应用,默认不选路由 ②通过一下命令分别创建2个模块和1个组件 ng g m hx1 ng g c hx1 ng g m hx ...