第9章 使用客户端凭据保护API
快速入门介绍了使用identityserver保护api的最基本方案。 我们将定义一个api和一个想要访问它的客户端。 客户端将通过提供clientcredentials
在identityserver请求访问令牌,clientcredentials
充当客户端和identityserver都知道的秘密,并且它将使用该令牌来访问api。
9.1设置asp.net核心应用程序
首先为应用程序创建一个目录 - 然后使用我们的模板创建一个包含基本identityserver设置的asp.net core应用程序,例如:
md quickstart cd quickstart md src cd src dotnet new is4empty -n identityserver
这将创建以下文件:
- identityserver.csproj- 项目文件和properties\launchsettings.json文件
- program.cs和startup.cs- 主要的应用程序入口点
- config.cs - identityserver资源和客户端配置文件
您现在可以使用自己喜欢的文本编辑器来编辑或查看文件。如果您希望获得visual studio支持,可以添加如下解决方案文件:
cd .. dotnet new sln -n quickstart
然后让它添加你的identityserver项目(记住这个命令,因为我们将在下面创建其他项目):
dotnet sln add .\src\identityserver\identityserver.csproj
注意
此模板中使用的协议是http
,当在kestrel
上运行时,端口设置为5000
或iisexpress
上的随机端口。您可以在properties\launchsettings.json
文件中更改它。但是,所有快速入门指令都假定您使用kestrel
上的默认端口以及http
协议,该协议足以进行本地开发。
9.2 定义api资源
api是您要保护的系统中的资源。
资源定义可以通过多种方式加载,模板使用“代码作为配置”appproach。在config.cs文件中,您可以找到一个名为getapisapi 的方法,如下所示:
public static ienumerable<apiresource> getapis() { return new list<apiresource> { new apiresource("api1", "my api") }; }
9.3 定义客户端
下一步是定义可以访问此api的客户端。
对于此方案,客户端将不具有交互式用户,并将使用identityserver的所谓客户端密钥进行身份验证。将以下代码添加到config.cs文件中:
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()) }, // scopes that client has access to allowedscopes = { "api1" } } }; }
9.4 配置identityserver
在startup.cs
加载资源和客户端定义 - 模板已经为您执行此操作:
public void configureservices(iservicecollection services) { var builder = services.addidentityserver() .addinmemoryidentityresources(config.getidentityresources()) .addinmemoryapiresources(config.getapis()) .addinmemoryclients(config.getclients()); // rest omitted }
就是这样 - 如果您运行服务器并浏览浏览器 http://localhost:5000/.well-known/openid-configuration
,您应该会看到所谓的发现文档。客户端和api将使用它来下载必要的配置数据。
首次启动时,identityserver将为您创建一个开发人员签名密钥,它是一个名为的文件tempkey.rsa
。您不必将该文件检入源代码管理中,如果该文件不存在,将重新创建该文件。
9.5 添加api
接下来,为您的解决方案添加api。
您可以使用visual studio中的asp.net core web api(或空)模板,也可以使用.net cli来创建api项目。从src
文件夹中运行以下命令:
dotnet new web -n api
然后通过运行以下命令将其添加到解决方案中:
cd .. dotnet sln add .\src\api\api.csproj
将api应用程序配置为http://localhost:5001
仅运行。您可以通过编辑properties文件夹中的launchsettings.json
文件来完成此操作。将应用程序url设置更改为:
"applicationurl": "http://localhost:5001"
9.6 控制器
在api项目中添加一个新文件夹controllers和一个新控制器identitycontroller
:
[route("identity")] [authorize] public class identitycontroller : controllerbase { [httpget] public iactionresult get() { return new jsonresult(from c in user.claims select new { c.type, c.value }); } }
这个控制器将在后面被用于测试授权需求,同时通过api的眼睛(浏览工具)来可视化身份信息。
9.7 配置
最后一步是将身份验证服务添加到di和身份验证中间件到管道。这些将:
- 验证输入的令牌以确保它来自可信任的发布者(identityserver)
- 验证令牌是否可用于该 api(也就是 scope)。
将startup
更新为如下所示:
public class startup { public void configureservices(iservicecollection services) { services.addmvccore() .addauthorization() .addjsonformatters(); services.addauthentication("bearer") .addjwtbearer("bearer", options => { options.authority = "http://localhost:5000"; options.requirehttpsmetadata = false; options.audience = "api1"; }); } public void configure(iapplicationbuilder app) { app.useauthentication(); app.usemvc(); } }
addauthentication
将身份验证服务添加到di并配置"bearer"
为默认方案。 useauthentication
将身份验证中间件添加到管道中,以便在每次调用主机时自动执行身份验证。
http://localhost:5001/identity
在浏览器上导航到控制器应返回401状态代码。这意味着您的api需要凭证,现在受identityserver保护。
9.8 创建客户端
最后一步是编写请求访问令牌的客户端,然后使用此令牌访问api。为此,在您的解决方案中添加一个控制台项目,请记住在以下位置创建它src:
dotnet new console -n client
然后和以前一样,使用以下方法将其添加到您的解
cd .. dotnet sln add .\src\client\client.csproj
打开program.cs并将内容从这里复制到它。
客户端程序异步调用main
方法以运行异步http
调用。 从c#7.1
开始,此功能可用,一旦您编辑client.csproj以将以下行添加为propertygroup
,它就可用:
<langversion>latest</langversion>
identityserver的令牌端点实现oauth 2.0协议,您可以使用原始http来访问它。但是,我们有一个名为identitymodel
的客户端库,它将协议交互封装在易于使用的api中。
将identitymodel
nuget包添加到您的客户端。这可以通过visual studio的nuget对话框,手动添加到client.csproj文件,或使用cli来完成:
dotnet add package identitymodel
identitymodel包括用于发现端点的客户端库。这样您只需要知道identityserver的基地址 - 可以从元数据中读取实际的端点地址:
// discover endpoints from metadata var client = new httpclient(); var disco = await client.getdiscoverydocumentasync("http://localhost:5000"); if (disco.iserror) { console.writeline(disco.error); return; }
接下来,您可以使用发现文档中的信息向identityserver请求令牌以访问api1:
// request token var tokenresponse = await client.requestclientcredentialstokenasync(new clientcredentialstokenrequest { address = disco.tokenendpoint, clientid = "client", clientsecret = "secret", scope = "api1" }); if (tokenresponse.iserror) { console.writeline(tokenresponse.error); return; } console.writeline(tokenresponse.json);
注意
将访问令牌从控制台复制并粘贴到以检查原始令牌。
9.9 调用
要将访问令牌发送到api,通常使用http authorization
标头。这是使用setbearertoken
扩展方法完成的:
// call api var client = new httpclient(); client.setbearertoken(tokenresponse.accesstoken); var response = await client.getasync("http://localhost:5001/identity"); if (!response.issuccessstatuscode) { console.writeline(response.statuscode); } else { var content = await response.content.readasstringasync(); console.writeline(jarray.parse(content)); }
输出应如下所示:
注意
默认情况下,访问令牌将包含有关范围(scope),生命周期(nbf和exp),客户端id(client_id)和颁发者名称(iss)的声明。
9.10 进一步的实验
本演练重点介绍了迄今为止的成功之路
- 客户端能够请求令牌
- 客户端可以使用令牌来访问api
你现在可以尝试引发一些错误来学习系统的相关行为,比如:
- 尝试在未运行时连接到identityserver(不可用)
- 尝试使用无效的客户端id或密码来请求令牌
- 尝试在令牌请求期间请求无效范围
- 尝试在api未运行时调用api(不可用)
- 不要将令牌发送到api
- 将api配置为需要与令牌中的范围不同的范围
推荐阅读
-
IdnentiyServer-使用客户端凭据访问API
-
IdnentiyServer使用客户端凭据访问API的实例代码
-
第9章 使用客户端凭据保护API
-
Identity Server 4 - Hybrid Flow - 使用ABAC保护MVC客户端和API资源
-
asp.net core系列 54 IS4用客户端凭据保护API
-
IdnentiyServer-使用客户端凭据访问API
-
IdnentiyServer使用客户端凭据访问API的实例代码
-
第9章 使用客户端凭据保护API
-
Identity Server 4 - Hybrid Flow - 使用ABAC保护MVC客户端和API资源
-
asp.net core系列 54 IS4用客户端凭据保护API