由于authenticated_client错误而无法获取令牌

时间:2018-12-17 17:52:36

标签: c# asp.net-core token access-token identityserver4

我正在撰写有关如何使用Postman从IDS4获取令牌的演示。

密码令牌请求取自IDS4's page

[HttpGet("token")]
public IActionResult GetToken([FromHeader] string user, [FromHeader] string pass)
{
  string tokenEndpoint = "https://localhost:44300/connect/token";
  HttpClient client = new HttpClient();

  Task<TokenResponse> tokenResponse = 
    client.RequestPasswordTokenAsync(new PasswordTokenRequest
  {
    Address = tokenEndpoint,

    ClientId = "client",
    ClientSecret = "client_secret",
    Scope = "MemberApi.full",

    UserName = user,
    Password = pass
  });
  TokenResponse toko = tokenResponse.Result;

  if (toko.IsError)
    return Ok(toko.Error);
  return Ok(toko.AccessToken;
}

客户端设置如下。

private static IEnumerable<Client> GetClients => new[]
{
  ...
  new Client
  {
    ClientId = "client",
    ClientSecrets = { new Secret("client_secret".Sha256()) },
    ClientName = "Client",

    AllowedGrantTypes = GrantTypes.Implicit,
    AllowAccessTokensViaBrowser = true,

    RedirectUris = { "http://localhost:5000/security/credentials" },
    PostLogoutRedirectUris = { "http://localhost:5000/index.html" },
    AllowedCorsOrigins = { "http://localhost:5000", "https://localhost:44300" },

    AllowedScopes =
    {
      IdentityServerConstants.StandardScopes.OpenId,
      IdentityServerConstants.StandardScopes.Profile,
      IdentityServerConstants.StandardScopes.Email,
      "MemberApi",
      "MemberApi.full",
      "MemberApi.limited"
    }
  }
};

API资源设置如下所示。

private static IEnumerable<ApiResource> GetApis => new[]
{
  new ApiResource
  {
    Name = "MemberApi",
    DisplayName = "Members' API",
    ApiSecrets = {new Secret("MemberSecret".Sha256())},
    UserClaims = {JwtClaimTypes.Name, JwtClaimTypes.Email, JwtClaimTypes.Role},
    Scopes = {new Scope("MemberApi.full"), new Scope("MemberApi.limited")}
  }
};

据我所知,我遵循了文档中的建议。我也尝试与示例进行比较。尽管如此,我仍然停留在错误消息 unauthorized_client 上。我会缺少什么?

2 个答案:

答案 0 :(得分:3)

此流程中不允许客户请求:

AllowedGrantTypes = GrantTypes.Implicit

忘记client.RequestPasswordTokenAsync。您不需要它,也无法使用它。在隐式流中,只有用户知道密码。对于客户来说这是遥不可及的。

假定IdentityServer在一个域上运行:https://idp.mydomain.com,而客户端在其他域上运行:https://mvc.mydomain.com

当用户点击mvc客户端上的安全页面时,该用户会被路由到用户登录的IdentityServer 。在那里,用户输入凭据,如果成功,则将用户返回到客户端。作为已知身份。

取决于流,客户端最终最终会获得至少一个访问令牌。此令牌很重要,因为它允许客户端代表用户访问资源 。就像门票一样。

基于访问令牌,资源现在知道WHO想要访问该资源。访问令牌有一个区分这一点的声明,即“子”声明。没有此声明,客户端将无法访问此流程中的资源。

在您的配置中,允许客户端访问“ MemberApi”作用域,但在实际访问资源之前,需要用户的同意。


如果要检索以最简单的流程开头的令牌,则为client credentials流。

这就是根本没有用户的流程。客户端(如在软件中)可以使用clientid + secret登录。如果配置正确,将产生访问令牌。

现在,客户端无需任何用户交互即可访问资源。身份令牌不可用,因为没有用户。缺少“子”要求。此流中不支持刷新令牌,不需要它。客户端可以使用凭据请求新令牌。


如果您想了解refresh token的工作方式,请在hybrid flow中用户登录,并另外(如果已配置scope = offline)返回刷新令牌。

由于访问令牌仅在短时间内有效(取决于到期时间),因此必须获取新令牌。为此,应使用刷新令牌。刷新令牌使客户端可以请求新的访问令牌,而无需用户交互(离线访问)。

使用新的访问令牌,直到它过期,并且必须请求一个新的令牌。直到刷新令牌本身过期为止,但是可以对其进行配置。


implicit flow中没有刷新令牌,但是访问令牌确实会全部过期。因此,您将需要另一种刷新令牌的方法。为此,您可以使用类似silent token renew的实现。

有关术语,请阅读documentation

请注意各种流程。这完全取决于环境。是否有用户,是否是浏览器应用程序,是否存在前通道,后通道,是否需要脱机访问,客户端可以保密吗?选择流之前需要考虑的事情。

选择流后,您需要为客户端配置允许的授予。如果仅允许隐式授予类型,则使用客户端凭据的客户端将无法访问资源。

IdentityServer主要用于配置客户端和资源。查看示例,以了解不同的流程以及如何配置它们。

答案 1 :(得分:0)

仅允许客户端使用隐式流来获取用于访问Identity Server保护的资源的令牌:

AllowedGrantTypes = GrantTypes.Implicit,

但是您的客户正在使用Resource Owner Flow

  
    

此赠款类型适用于能够获得        资源所有者的凭证(用户名和密码,通常使用        互动形式)。它还用于迁移现有客户端        使用直接身份验证方案,例如HTTP Basic或Digest        通过将存储的凭据转换为OAuth进行身份验证        访问令牌。

  

如果您使用的是SPA应用程序,则应使用“隐式流程”获取令牌,而不必将最终用户凭据暴露给第三方。

通常,您有三个应用程序:客户端应用程序,身份服务器(带有用户db)和api。使用隐式流时:

  1. 客户端会将用户重定向到身份服务器应用程序,身份服务器提供UI以便用户输入其凭据。
  2. 用户输入凭据后,身份服务器将验证DB /配置文件中的凭据。当然,您也可以在身份服务器中配置外部登录。
  3. 验证凭据后,身份服务器将根据客户端的OpenID Connect配置中的回调URL向您的客户端应用颁发ID令牌和访问令牌(如果范围包括API资源)。
  4. 客户端应用将验证并解码ID令牌和登录用户。您可以使用SDK或直接手动处理该过程。
  5. 如果获得访问令牌,则可以将访问令牌保留在会话缓存中,它可以用于访问受保护的资源,直到过期为止。