一. 概述

  本篇开始进入IS4实战学习,从第一个示例开始,该示例是 “使用客户端凭据保护API”,这是使用IdentityServer保护api的最基本场景。该示例涉及到三个项目包括:IdentityServer项目、API项目、Client项目,都有自己的宿主,为了方便开发,放在了一个解决方案下(Quickstart.sln),三个项目的分工如下:

(1) IdentityServer项目是包含基本的IdentityServer设置的ASP.NET Core应用程序,是令牌端点。

(2) API项目是Web Api,是要保护的资源。

(3) Client项目是客户端用户,用来访问Web Api。

  最后客户端Client项目请求获取IdentityServer上的访问令牌。作为客户端Client和IdentityServer都知道secret密钥,Client将使用令牌访问Web API。开源地址Github

 

二. 创建IdentityServer项目 

  创建一个ASP.NET Core Web(或空)模板。项目名为IdentityServer,解决方案为Quickstart。是一个包含基本IdentityServer设置的ASP.NET Core应用程序。该项目使用的协议是http,当在Kestrel上运行时,端口设置为5000或在IISExpress上的随机端口。

  首次启动时,IdentityServer将为您创建一个开发人员签名密钥,它是一个名为的文件tempkey.rsa。您不必将该文件检入源代码管理中,如果该文件不存在,将重新创建该文件。项目最终目录结构如下所示:

  下面进行说明,以及用序号来表示开发实现步骤:

  2.1 安装:Install-Package IdentityServer4

  2.2 新增Config.cs文件, 该文件是IdentityServer资源和客户端配置文件。在该文件中定义API资源,以及定义客户端(可以访问此API的客户端)

        /// <summary>
/// 定义API资源,要保护的资源
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiResource> GetApis()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API")
};
}
        /// <summary>
/// 定义客户端,可以访问此API的客户端
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "client", // no interactive user, use the clientid/secret for authentication
AllowedGrantTypes = GrantTypes.ClientCredentials, //使用密钥进行身份认证 secret for authentication
ClientSecrets =
{
new Secret("secret".Sha256())
}, //客户端允许访问的范围
AllowedScopes = { "api1" }
}
};
}

  2.3 Startup配置    

        /// <summary>
/// 配置IdentityServer,加载API资源和客户端
/// </summary>
/// <param name="services"></param>
public void ConfigureServices(IServiceCollection services)
{
// uncomment, if you wan to add an MVC-based UI
//services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
//添加AddIdentityServer
var builder = services.AddIdentityServer()
//添加内存的Identity资源
.AddInMemoryIdentityResources(Config.GetIdentityResources())
//添加api资源
.AddInMemoryApiResources(Config.GetApis())
//添加clinet
.AddInMemoryClients(Config.GetClients()); if (Environment.IsDevelopment())
{
          //开发环境下使用临时签名凭据
builder.AddDeveloperSigningCredential();
}
else
{
throw new Exception("need to configure key material");
}
}
        public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} // uncomment if you want to support static files
//app.UseStaticFiles(); app.UseIdentityServer(); // uncomment, if you wan to add an MVC-based UI
//app.UseMvcWithDefaultRoute();
}

  运行服务器并浏览浏览器 http://localhost:5000/.well-known/openid-configuration, 客户端和API将使用它来下载必要的配置数据。下面是截取的部分配置数据:

三. 创建API项目

  在解决方案下继续添加API项目,添加ASP.NET Core Web API(或空)模板。将API应用程序配置为http://localhost:5001运行。项目最终目录结构如下所示:

  (1) 在API项目中添加一个新文件夹Controllers和一个新控制器IdentityController

   //定义路由
[Route("identity")]
//需要授权
[Authorize]
public class IdentityController : ControllerBase
{
/// <summary>
/// 测试授权,获取该用户下声明集合Claims
/// </summary>
/// <returns></returns>
public IActionResult Get()
{
return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
}
}

  (2) Startup配置

    public void ConfigureServices(IServiceCollection services)
{
//将最基本的MVC服务添加到服务集合中
services.AddMvcCore()
//向基本的MVC服务中添加授权
.AddAuthorization()
//向基本的MVC服务中添加格式化
.AddJsonFormatters(); //将身份验证服务添加到DI服务集合中,并配置"Bearer"为默认方案
services.AddAuthentication("Bearer")
//验证令牌是否有效用于此API
.AddJwtBearer("Bearer", options =>
{
options.Authority = "http://localhost:5000";
//在开发环境禁用,默认true
options.RequireHttpsMetadata = false;
            //订阅者资源范围
options.Audience = "api1";
});
}
        public void Configure(IApplicationBuilder app)
{
//添加身份验证中间件
app.UseAuthentication();
app.UseMvc();
}

    启动程序运行http://localhost:5001/identity时返回401状态码,未授权。意味着API需要凭证,现在受IdentityServer保护。如下所示:

四.创建Client项目

  我们通过上面知道,直接用浏览器来访问API是返回401状态码未授权,下面在Client项目中使用凭证,来获得api授权访问。下面是Client项目目录结构,这里Client是一个控制台应用程序。对于客户端可以是任意应用程序,比如手机端,web端,win服务等等。

  在IdentityServer的令牌端点实现了OAuth 2.0协议,客户端可以使用原始HTTP来访问它。但是,我们有一个名为IdentityModel的客户端库,它将协议交互封装在易于使用的API中。

  3.1  安装:Install-Package IdentityModel

  3.2  发现IdentityServer端点

    IdentityModel包括用于发现端点的客户端库。只需要知道IdentityServer的基地址 - 可以从元数据中读取实际的端点地址:

        private static async Task Main()
{
// discover endpoints from metadata
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
if (disco.IsError)
{
//当停掉IdentityServer服务时
//Error connecting to http://localhost:5000/.well-known/openid-configuration: 由于目标计算机积极拒绝,无法连接。
Console.WriteLine(disco.Error);
return;
}
     //...

    其中GetDiscoveryDocumentAsync是属于IdentityModel库的,是对HttpClient扩展方法。http://localhost:5000是IdentityServer的基地址。

  3.3  请求令牌Token

    在Mian方法中继续向IdentityServer请求令牌,访问api1资源。这里的RequestClientCredentialsTokenAsync方法也是HttpClient扩展方法。

            // request token,带入需要的4个参数,请求令牌,返回TokenResponse
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
//IdentityServer基地址 http://localhost:5000/connect/token
Address = disco.TokenEndpoint,
//设置客户端标识
ClientId = "client",
//设置密钥
ClientSecret = "secret",
//访问的资源范围
Scope = "api1"
}); if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
return;
}
//打印 token 信息
Console.WriteLine(tokenResponse.Json);
Console.WriteLine("\n\n");

  3.4 调用API

    在Mian方法中继续向下,当访问令牌取得后,开始调用Web API。 下面将访问令牌发送到Web API,通常使用HTTP Authorization标头。这是使用SetBearerToken扩展方法完成的,该方法是IdentityModel库的HttpClient扩展方法。

            // call api
var apiClient = new HttpClient();
//发送访问令牌
apiClient.SetBearerToken(tokenResponse.AccessToken); //访问API,获取该用户下声明集合Claims
var response = await apiClient.GetAsync("http://localhost:5001/identity");
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
}
else
{
//输出 claims 名称值 对
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(JArray.Parse(content));
}

    下面开始测试,先启动IdentityServer程序,再启动API程序,最后启动Client客户端来访问API,通过下图可以了解到:(1)客户端请求令牌成功,(2) 客户端使用令牌来访问API成功。

如果想进一步尝试激发错误,来了解系统的行为,可以错误的去配置如下:

    (1) 尝试停掉IdentityServer服务程序,这个已经测试了。

    (2) 尝试使用无效的客户端ID标识  ClientId = "client",

    (3) 尝试在令牌请求期间请求无效范围 Scope = "api1"

    (4) 尝试在API程序未运行时调用API

    (5) 尝试不要将令牌发送到API

  

  总结:通过本篇了解到了IS4保护api的最基本场景。流程是首先创建一个IdentityServer 令牌程序。 接着创建API项目,使用IdentityServer令牌程序来保护API。 最后创建要访问的Client项目,获取访问令牌后再调用API方法。

    IdentityServer令牌端对要保护API资源做了配置 new ApiResource("api1", "My API")

    限制了访问Api的客户端标识和访问资源范围ClientId = "client", AllowedScopes = { "api1" }还有客户端需要的秘钥。

  参考文献

    使用客户端凭据保护API

asp.net core系列 54 IS4用客户端凭据保护API的更多相关文章

  1. 【IdentityServer4文档】- 使用客户端凭据保护 API

    使用客户端凭据保护 API quickstart 介绍了使用 IdentityServer 保护 API 的最基本场景. 接下来的场景,我们将定义一个 API 和一个想要访问它的客户端. 客户端将在 ...

  2. asp.net core系列 55 IS4结合Identity密码保护API

    一.概述 OAuth 2.资源所有者密码授权允许客户端(Client项目)向令牌服务(IdentityServer项目)发送用户名和密码,并获取代表该用户的访问令牌.本篇将IS4结合asp.net c ...

  3. asp.net core系列 55 IS4使用Identity密码保护API

    一.概述 OAuth 2.0资源(web api)所有者密码授权,允许客户端(Client项目)向令牌服务(IdentityServer项目)发送用户名和密码,并获取代表该用户的访问令牌.在官方文档中 ...

  4. 第9章 使用客户端凭据保护API - Identity Server 4 中文文档(v1.0.0)

    快速入门介绍了使用IdentityServer保护API的最基本方案. 我们将定义一个API和一个想要访问它的客户端. 客户端将通过提供ClientCredentials在IdentityServer ...

  5. asp.net core系列 58 IS4 基于浏览器的JavaScript客户端应用程序

    一. 概述 本篇探讨使用"基于浏览器的JavaScript客户端应用程序".与上篇实现功能一样,只不过这篇使用JavaScript作为客户端程序,而非core mvc的后台代码Ht ...

  6. asp.net core系列 57 IS4 使用混合流(OIDC+OAuth2.0)添加API访问

    一.概述 在上篇中,探讨了交互式用户身份验证,使用的是OIDC协议. 在之前篇中对API访问使用的是OAuth2.0协议.这篇把这两个部分放在一起,OpenID Connect和OAuth 2.0组合 ...

  7. asp.net core系列 56 IS4使用OpenID Connect添加用户认证

    一.概述 在前二篇中讲到了客户端授权的二种方式: GrantTypes.ClientCredentials凭据授权和GrantTypes.ResourceOwnerPassword密码授权,都是OAu ...

  8. 【目录】asp.net core系列篇

    随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...

  9. Ajax跨域问题及解决方案 asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS) c#中的Cache缓存技术 C#中的Cookie C#串口扫描枪的简单实现 c#Socket服务器与客户端的开发(2)

    Ajax跨域问题及解决方案   目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...

随机推荐

  1. Linux的动态库与静态库

    1.动态库与静态库简介 在实际的软件开发中,为了方便使用一些被重复调用的公共代码,我们经常将这些公共的函数编译成动态库或静态库.我们知道程序一般要经过预处理.编译.汇编和链接这几个步骤才能变成可执行的 ...

  2. java之Spring(AOP)前奏-动态代理设计模式(上)

    我们常常会遇到这样的事,项目经理让你为一个功能类再加一个功能A,然后你加班为这个类加上了功能A: 过了两天又来了新需求,再在A功能后面加上一个新功能B,你加班写好了这个功能B,加在了A后面:又过 了几 ...

  3. MySQL数据库主从分离的配置方法

    1.介绍 MySQL数据库设置读写分离,可以使对数据库的写操作和读操作在不同服务器上执行,提高并发量和响应速度.现在的网站一般大点的,都采用有数据库主从分离.读写分离,既起到备份作用也可以减轻数据库的 ...

  4. Java(四、类和对象)

    Java 对象和类 Java作为一种面向对象语言.支持以下基本概念: 多态.继承.封装.抽象.类.对象.实例.方法.重载 对象 对象是类的一个实例(对象不是找个女朋友),有状态和行为.例如,一条狗是一 ...

  5. HTML DOM对象的属性和方法

    HTML DOM对象的属性和方法 HTML DOM 对象有几种类型: 1.Document 类型 在浏览器中,Document 对象表示整个 HTML 文档. 1.1属性 引用文档的子节点 docum ...

  6. 集成支付宝,报警告warning: (arm64) /Users/tommy/Desktop/Project/ios-msdk-git/AlipaySDK4Standard/AlipaySDK/Library/UTDI

    集成支付宝的时候遇到的问题,找到了解决办法,还说明了原因,非常好,觉得应该记下来,反正以我的记性下次一定是会忘光光哒~ 1)  Go to Build Settings -> Build Opt ...

  7. python捕获异常、处理异常

    https://blog.csdn.net/jmilk/article/details/50047457

  8. RNN(Recurrent Neural Network)的几个难点

    1. vanish of gradient RNN的error相对于某个时间点t的梯度为: \(\frac{\partial E_t}{\partial W}=\sum_{k=1}^{t}\frac{ ...

  9. 用redis的scan命令代替keys命令,以及在spring-data-redis中遇到的问题

    摘要 本文主要是介绍使用redis scan命令遇到的一些问题总结,scan命令本身没有什么问题,主要是spring-data-redis的问题. 需求 需要遍历redis中key,找到符合某些pat ...

  10. 网络IO和磁盘IO详解

    1. 缓存IO 缓存I/O又被称作标准I/O,大多数文件系统的默认I/O操作都是缓存I/O.在Linux的缓存I/O机制中,数据先从磁盘复制到内核空间的缓冲区,然后从内核空间缓冲区复制到应用程序的地址 ...