Identity Server 4的授权客户自定义端点

5
我希望我的身份认证服务器 Identity Server 4 可以为某些注册客户端提供额外的服务(例如 "MyAdditionalService")。这项服务将通过在服务器上定义的自定义端点由他们使用。
我考虑为该服务定义一个 API(例如名为 "myAdditionalService"),以便根据配置向客户授予对此类服务的访问权限。但是,我不确定如何限制访问端点(MVC - Action 方法),仅允许允许使用API的客户端(可能代表用户)访问。
我发现可以使用以下方法:
services.AddAuthorization(options =>
     {
       options.AddPolicy("MyAdditionalServicePolicy",
           policy => policy.RequireClaim("scope", 
           "myAdditionalService"));
      });

您需要使用属性[Authorize("MyAdditionalServicePolicy")]来装饰用于访问此类服务的动作方法。但是,我不知道服务器是否可以同时充当API,甚至是否可能。

如何实现这一点?令人困惑的是,令牌服务也扮演着API的角色,因为它保护了对动作方法或端点的访问。

谢谢。


更新:

我的Web应用程序是IdentityServerWithAspNetIdentity,已经使用了Asp.net core Identity的身份验证机制。为了举例说明,我的Web应用程序提供给某些注册客户的附加服务是用户的Twitter好友列表(建模在名为Twitter的控制器上,动作名为ImportFriends),因此API被称为“TwitterFriends”。

根据下面的响应建议,我修改了Configure()方法,使其具有app.UseJwtBearerAuthentication()。我已经像下面显示的那样使用了app.UseIdentity()app.UseIdentityServer()

        app.UseIdentity();
        app.UseIdentityServer();


        app.UseJwtBearerAuthentication(new JwtBearerOptions
        {
            AuthenticationScheme = "Bearer",
            Authority = Configuration["BaseUrl"],
            Audience = "TwitterFriends",
            RequireHttpsMetadata = false                 //TODO: make true, it is false for development only
        });

        // Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715
        app.UseGoogleAuthentication(new GoogleOptions
        {
            AuthenticationScheme = "Google",
            SignInScheme = "Identity.External", // this is the name of the cookie middleware registered by UseIdentity()

而在专用控制器上:

 [Authorize(ActiveAuthenticationSchemes = "Identity.Application,Bearer")]
//[Authorize(ActiveAuthenticationSchemes = "Identity.Application")]
//[Authorize(ActiveAuthenticationSchemes = "Bearer")]
[SecurityHeaders]
public class TwitterController : Controller
{...

但是我在日志中看到了这个:
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware
[7]
      Identity.Application was not authenticated. Failure message: Unprotect tic
ket failed
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed for user: (null).
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.A
uthorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
      Executing ChallengeResult with authentication schemes (Identity.Applicatio
n, Bearer).
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware
[12]
      AuthenticationScheme: Identity.Application was challenged.
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[12]
      AuthenticationScheme: Bearer was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action IdentityServerWithAspNetIdentity.Controllers.TwitterContro
ller.ImportFriends (IdentityServerWithAspNetIdentity) in 86.255ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 105.2844ms 401

我尝试了不同的属性组合,但在这种情况下,Identity.Application和Bearer似乎无法共存:会收到401错误。

非常感谢任何帮助。

2个回答

6
看这个例子,了解如何在同一个Web应用程序中托管API和IdentityServer。 https://github.com/brockallen/IdentityServerAndApi 基本上,您需要添加JWT令牌验证处理程序: services.AddAuthentication() .AddJwtBearer(jwt => { jwt.Authority = "IdentityServer的基础地址"; jwt.Audience = "API的名称"; }); 在API本身上,必须选择JWT身份验证方案: public class TestController : ControllerBase { [Route("test")] [Authorize(AuthenticationSchemes = "Bearer")] public IActionResult Get() { var claims = User.Claims.Select(c => new { c.Type, c.Value }).ToArray(); return Ok(new { message = "Hello API", claims }); } } 如果您想强制执行其他授权策略,可以将其传递到[Authorize]属性中或以命令方式调用它。

我的Web应用程序是一个IdentityServerWithAspNetIdentity,它已经使用了Asp.net核心身份验证机制。我不确定是否会有冲突,因为我正在学习所有这些内容,尝试添加第二个身份验证渠道。 - VMh
当我将AddJwtBearer(.net core 1.1的app.UseJwtBearerAuthentication)与IdentityServerWithAspNetIdentity中的内容结合时,我遇到了401错误。不确定出了什么问题。我更新了问题,并提供了有关我尝试过的内容和日志信息。任何帮助都将不胜感激。谢谢。 - VMh

2
为了实现这一点,首先需要编写一些策略。策略将定义特定 API 的可访问范围。因此,您将为已注册的客户端分配一些范围。假设范围名称为“仅限已注册客户端的 API”。
我们将创建以下策略:
        services.AddAuthorization(options =>
        {
            options.SetRegisteredClientsPolicy();
        }

并且。
  private static void RequireScope(this AuthorizationPolicyBuilder authorizationPolicyBuilder, string[] values)
    {
        authorizationPolicyBuilder.RequireClaim("scope", values);
    }

private static void SetRegisteredClientsPolicy(this AuthorizationOptions options)
{
    options.AddPolicy(
                  OpenIdPolicies.Clients.RegisteredClients,
                  policyBuilder =>
                  {
                      policyBuilder.RequireAuthenticatedUser();
                      policyBuilder.RequireScope(new string[] { "ApiOnlyForRegisteredClients" });
                  });
}

一旦完成,您就完成了策略创建。

在创建访问令牌时,请确保将"ApiOnlyForRegisteredClients"的相同值放入范围声明中。

现在我们需要添加一个API并使用[Authorize]属性进行标记。

   [Authorize(AuthenticationSchemes = "Bearer", Policy = OpenIdPolicies.Clients.RegisteredClients)]
    public async Task<ActionResult<T>> Post(int userId, [FromBody] List<int> simRoleIds)
    {
    }

现在我们需要添加JWT身份验证中间件。
.AddJwtBearer("Bearer", options =>
   {
       options.Authority = configuration["AuthorityAddresses"];
       options.RequireHttpsMetadata = Convert.ToBoolean(configuration["RequireHttpsMetadata"]);
       options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
       {
           TokenDecryptionKey = new X509SecurityKey()
           ValidAudiences = apiResources.Select(x => x.ResourceName).ToList(),
           ValidIssuers = new List<string> { authorityAddressWithHttps.Uri.OriginalString, authorityAddressWithBasePathHttps.Uri.OriginalString, configuration["AuthorityAddresses"] }
       };
   })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接