身份服务器 4
Identity Server 4
初学者级别的查询警报。 IdentityServer4 Tutorial 看完教程后我推断是-
- 我创建了一个授权服务器,其工作是通过适当的身份验证为客户端颁发令牌。
- 首先是我的授权服务器 运行,包括 API 和客户端的信息和定义。
- API 有一个验证传入令牌的身份验证中间件,以确保它是否来自受信任的来源及其范围。
- 客户端从授权服务器请求令牌,然后将请求发送到 API 并收到令牌。
对于所有这些,我必须先 运行 授权服务器,然后是 API,然后是客户端。我的要求是我不需要单独启动和停止服务器 运行 来处理身份验证。我有一个 API,我也需要它兼作授权服务器。这可能吗? API 是否有可能生成令牌、验证它们然后处理请求,同时一直使用 IdentityServer4。
2020 年 1 月更新:对于在与 ASP.NET 核心 API 控制器相同的项目中使用 IdentityServer4 的 ASP.NET 核心 3.1 示例,你可以看看我的IdentityServer4 with MVC Controllers and AppInsights sample repo。它的目标是测试 AppInsights,但它确实演示了一个 SPA 存根,它调用两个 OpenID 端点(⚠ 在 non-recommended wa 中,使用客户端凭据)和控制器端点。
虽然通常 Auth Server 将与 Resource Server 分开,但这并不需要是这种情况。您可以将所有这些添加到一个应用程序中。这是一个例子。
- 创建一个新的 ASP.NET Core(我用的是 2.0)Web API 应用程序。
Install-Package IdentityServer4 -Version 2.0.0-rc1
(在编写 rc1 时是支持 .NET Core 2.x 的版本)
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
- 通过模板在
ValuesController
上设置 [Authorize]
将此代码添加到 class Startup
上面 app.UseMvc()
中的 Configure(...)
:
// calls app.UseAuthentication() for us
// See: http://docs.identityserver.io/en/release/quickstarts/6_aspnet_identity.html
app.UseIdentityServer();
将此代码添加到 class Startup
中的 ConfigureServices(...)
:
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(new[]
{
new ApiResource
{
Name = "MyApi",
ApiSecrets = { new Secret("supersecret".Sha256()) },
Scopes = { new Scope("myapi") },
}
})
.AddInMemoryClients(new[]
{
new Client
{
ClientId = "api",
ClientSecrets = { new Secret("supersecret".Sha256()) },
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowedScopes = { "myapi" },
}
})
.AddTestUsers(new List<TestUser>
{
new TestUser
{
SubjectId = "some-unique-id-12345678980",
Username = "john",
Password = "123456"
}
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opts =>
{
opts.Authority = "http://localhost:51689";
opts.Audience = "MyApi";
opts.RequireHttpsMetadata = !env.IsDevelopment();
});
如果您现在 F5 应用程序,它将显示一个空白页面,因为“401 未经授权”响应。您现在还可以检查此端点:http://localhost:51689/.well-known/openid-configuration
(当然还有您的开发端口)。
您现在也可以这样做:
curl -X POST \
http://localhost:51689/connect/token \
-H 'authorization: Basic YXBpY2xpZW50aWQ6c3VwZXJzZWNyZXQ=' \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded' \
-d 'username=john&password=123456&grant_type=password'
请注意 authorization
header 包含表示字符串 "apiclientid:supersecret"
的 base64 编码字符串。这应该会给你这样的结果:
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjczODhkMjY0MDg4Y2NjOGRiZTcwODIzZGIxYzY3ZWNkIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDUwODE3OTAsImV4cCI6MTUwNTA4NTM5MCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MTY4OSIsImF1ZCI6WyJodHRwOi8vbG9jYWxob3N0OjUxNjg5L3Jlc291cmNlcyIsIk15QXBpIl0sImNsaWVudF9pZCI6ImFwaWNsaWVudGlkIiwic3ViIjoic29tZS11bmlxdWUtaWQtMTIzNDU2Nzg5ODAiLCJhdXRoX3RpbWUiOjE1MDUwODE3OTAsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsibXlhcGkiXSwiYW1yIjpbInB3ZCJdfQ.sxWodlJKDJgjoOj-8njZ8kONOqiKgj3E5YlKXGX5cz-WqUK7RHKJacNX09D00Y8YtmZpkc5OrY0xzOx7UuSAtDku4oOX_1o38XEGJPBSJHdjqgVGSOU-hwDkzin8HSRJ0Kna1vM3ZzTh80cFTVhP8h903GAPRrAyV8PtRXnwV0CPel8NdvML6dV-mfDpGi0l7crp-TPnH4nIG0olpRYUPV5EsgCVMG9vswnOnKz3RPOGaU8yJy7_9mbQW5GHKfN0J6swiSt5rY3NKs_t1P9-tnCDKBOAafaXjLEO3Kx4fP4xTgwK92uKcEDDnRZo_-T0CkBxnSQm0oz1sUyrW8_3Pg",
"expires_in": 3600,
"token_type": "Bearer"
}
除了切换到其他身份验证流程的选项外,您还可以添加这样的控制器方法:
[Route("api/token")]
public class TokenController
{
[HttpPost("request")]
public async Task<JObject> Request(string username, string password)
{
var tokenClient = new TokenClient("http://localhost:51689/connect/token", "apiclientid", "supersecret");
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync(username, password);
if (tokenResponse.IsError) { /* Log failed login attempt! */ }
return tokenResponse.Json;
}
}
然后这样称呼它:
curl -X POST \
http://localhost:51689/api/token/request \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded' \
-d 'username=john&password=123456'
这应该给出与上面类似的响应。
您现在可以像这样提供 access_token
插入 header Authorization: Bearer access_token_should_go_here
:
curl -X GET \
http://localhost:51689/api/values \
-H 'authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjczODhkMjY0MDg4Y2NjOGRiZTcwODIzZGIxYzY3ZWNkIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDUwODIyODQsImV4cCI6MTUwNTA4NTg4NCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MTY4OSIsImF1ZCI6WyJodHRwOi8vbG9jYWxob3N0OjUxNjg5L3Jlc291cmNlcyIsIk15QXBpIl0sImNsaWVudF9pZCI6ImFwaWNsaWVudGlkIiwic3ViIjoic29tZS11bmlxdWUtaWQtMTIzNDU2Nzg5ODAiLCJhdXRoX3RpbWUiOjE1MDUwODIyODQsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsibXlhcGkiXSwiYW1yIjpbInB3ZCJdfQ.hQ60zzEbZOSVpP54yGAnnzfVEks18YXn3gU2wfFgNB33UxQabk1l3xkaeUPTpuFdmFTm4TbVatPaziGqaxjzYgfdVoAwQ3rYJMuYzOh0kUowKxXTkquAlD13ScpvxrGeCXGxFTRHrxX2h-1hHGQ9j2y2f3-ESynzrCdxp5HEH1271BSYfQ7pZIzvyxxpbmOzzKDzdYfcJV6ocnOU4jXBhw6iOzqpR03zxxtjIjGbJd2QwWklBGqZlO_thdZZFi-t7zu5eC4wqRCYGGZYWOUC17_Btc_Irg2SsvLCUDzsaBw7AVgLpZ7YjF-RsVqIi6oxNQ2K0zllzUy8VbupbWKr5Q' \
-H 'cache-control: no-cache' \
现在您应该通过 [Authorize]
属性。耶!
您现在有一个 Web 应用程序,它同时充当 Auth Server 和 Resource Server。
有趣的事实:在上面的示例中,AddJwtBearer
选项将应用程序自己的 url 指定为 Authority
,使应用程序从自身请求 public 键用于验证令牌。您也可以使用代码直接将此密钥提供给身份验证中间件。
初学者级别的查询警报。 IdentityServer4 Tutorial 看完教程后我推断是-
- 我创建了一个授权服务器,其工作是通过适当的身份验证为客户端颁发令牌。
- 首先是我的授权服务器 运行,包括 API 和客户端的信息和定义。
- API 有一个验证传入令牌的身份验证中间件,以确保它是否来自受信任的来源及其范围。
- 客户端从授权服务器请求令牌,然后将请求发送到 API 并收到令牌。
对于所有这些,我必须先 运行 授权服务器,然后是 API,然后是客户端。我的要求是我不需要单独启动和停止服务器 运行 来处理身份验证。我有一个 API,我也需要它兼作授权服务器。这可能吗? API 是否有可能生成令牌、验证它们然后处理请求,同时一直使用 IdentityServer4。
2020 年 1 月更新:对于在与 ASP.NET 核心 API 控制器相同的项目中使用 IdentityServer4 的 ASP.NET 核心 3.1 示例,你可以看看我的IdentityServer4 with MVC Controllers and AppInsights sample repo。它的目标是测试 AppInsights,但它确实演示了一个 SPA 存根,它调用两个 OpenID 端点(⚠ 在 non-recommended wa 中,使用客户端凭据)和控制器端点。
虽然通常 Auth Server 将与 Resource Server 分开,但这并不需要是这种情况。您可以将所有这些添加到一个应用程序中。这是一个例子。
- 创建一个新的 ASP.NET Core(我用的是 2.0)Web API 应用程序。
Install-Package IdentityServer4 -Version 2.0.0-rc1
(在编写 rc1 时是支持 .NET Core 2.x 的版本)Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
- 通过模板在
ValuesController
上设置[Authorize]
将此代码添加到
class Startup
上面app.UseMvc()
中的Configure(...)
:// calls app.UseAuthentication() for us // See: http://docs.identityserver.io/en/release/quickstarts/6_aspnet_identity.html app.UseIdentityServer();
将此代码添加到
class Startup
中的ConfigureServices(...)
:services.AddIdentityServer() .AddDeveloperSigningCredential() .AddInMemoryApiResources(new[] { new ApiResource { Name = "MyApi", ApiSecrets = { new Secret("supersecret".Sha256()) }, Scopes = { new Scope("myapi") }, } }) .AddInMemoryClients(new[] { new Client { ClientId = "api", ClientSecrets = { new Secret("supersecret".Sha256()) }, AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, AllowedScopes = { "myapi" }, } }) .AddTestUsers(new List<TestUser> { new TestUser { SubjectId = "some-unique-id-12345678980", Username = "john", Password = "123456" } }); services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(opts => { opts.Authority = "http://localhost:51689"; opts.Audience = "MyApi"; opts.RequireHttpsMetadata = !env.IsDevelopment(); });
如果您现在 F5 应用程序,它将显示一个空白页面,因为“401 未经授权”响应。您现在还可以检查此端点:http://localhost:51689/.well-known/openid-configuration
(当然还有您的开发端口)。
您现在也可以这样做:
curl -X POST \
http://localhost:51689/connect/token \
-H 'authorization: Basic YXBpY2xpZW50aWQ6c3VwZXJzZWNyZXQ=' \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded' \
-d 'username=john&password=123456&grant_type=password'
请注意 authorization
header 包含表示字符串 "apiclientid:supersecret"
的 base64 编码字符串。这应该会给你这样的结果:
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjczODhkMjY0MDg4Y2NjOGRiZTcwODIzZGIxYzY3ZWNkIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDUwODE3OTAsImV4cCI6MTUwNTA4NTM5MCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MTY4OSIsImF1ZCI6WyJodHRwOi8vbG9jYWxob3N0OjUxNjg5L3Jlc291cmNlcyIsIk15QXBpIl0sImNsaWVudF9pZCI6ImFwaWNsaWVudGlkIiwic3ViIjoic29tZS11bmlxdWUtaWQtMTIzNDU2Nzg5ODAiLCJhdXRoX3RpbWUiOjE1MDUwODE3OTAsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsibXlhcGkiXSwiYW1yIjpbInB3ZCJdfQ.sxWodlJKDJgjoOj-8njZ8kONOqiKgj3E5YlKXGX5cz-WqUK7RHKJacNX09D00Y8YtmZpkc5OrY0xzOx7UuSAtDku4oOX_1o38XEGJPBSJHdjqgVGSOU-hwDkzin8HSRJ0Kna1vM3ZzTh80cFTVhP8h903GAPRrAyV8PtRXnwV0CPel8NdvML6dV-mfDpGi0l7crp-TPnH4nIG0olpRYUPV5EsgCVMG9vswnOnKz3RPOGaU8yJy7_9mbQW5GHKfN0J6swiSt5rY3NKs_t1P9-tnCDKBOAafaXjLEO3Kx4fP4xTgwK92uKcEDDnRZo_-T0CkBxnSQm0oz1sUyrW8_3Pg",
"expires_in": 3600,
"token_type": "Bearer"
}
除了切换到其他身份验证流程的选项外,您还可以添加这样的控制器方法:
[Route("api/token")]
public class TokenController
{
[HttpPost("request")]
public async Task<JObject> Request(string username, string password)
{
var tokenClient = new TokenClient("http://localhost:51689/connect/token", "apiclientid", "supersecret");
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync(username, password);
if (tokenResponse.IsError) { /* Log failed login attempt! */ }
return tokenResponse.Json;
}
}
然后这样称呼它:
curl -X POST \
http://localhost:51689/api/token/request \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded' \
-d 'username=john&password=123456'
这应该给出与上面类似的响应。
您现在可以像这样提供 access_token
插入 header Authorization: Bearer access_token_should_go_here
:
curl -X GET \
http://localhost:51689/api/values \
-H 'authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjczODhkMjY0MDg4Y2NjOGRiZTcwODIzZGIxYzY3ZWNkIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDUwODIyODQsImV4cCI6MTUwNTA4NTg4NCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MTY4OSIsImF1ZCI6WyJodHRwOi8vbG9jYWxob3N0OjUxNjg5L3Jlc291cmNlcyIsIk15QXBpIl0sImNsaWVudF9pZCI6ImFwaWNsaWVudGlkIiwic3ViIjoic29tZS11bmlxdWUtaWQtMTIzNDU2Nzg5ODAiLCJhdXRoX3RpbWUiOjE1MDUwODIyODQsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsibXlhcGkiXSwiYW1yIjpbInB3ZCJdfQ.hQ60zzEbZOSVpP54yGAnnzfVEks18YXn3gU2wfFgNB33UxQabk1l3xkaeUPTpuFdmFTm4TbVatPaziGqaxjzYgfdVoAwQ3rYJMuYzOh0kUowKxXTkquAlD13ScpvxrGeCXGxFTRHrxX2h-1hHGQ9j2y2f3-ESynzrCdxp5HEH1271BSYfQ7pZIzvyxxpbmOzzKDzdYfcJV6ocnOU4jXBhw6iOzqpR03zxxtjIjGbJd2QwWklBGqZlO_thdZZFi-t7zu5eC4wqRCYGGZYWOUC17_Btc_Irg2SsvLCUDzsaBw7AVgLpZ7YjF-RsVqIi6oxNQ2K0zllzUy8VbupbWKr5Q' \
-H 'cache-control: no-cache' \
现在您应该通过 [Authorize]
属性。耶!
您现在有一个 Web 应用程序,它同时充当 Auth Server 和 Resource Server。
有趣的事实:在上面的示例中,AddJwtBearer
选项将应用程序自己的 url 指定为 Authority
,使应用程序从自身请求 public 键用于验证令牌。您也可以使用代码直接将此密钥提供给身份验证中间件。