根据客户添加访问令牌的声明

时间:2019-03-04 13:27:00

标签: asp.net-core .net-core identityserver4

我遇到这样的情况:一个Web应用程序需要具有一个声明的访问令牌,而另一个Web应用程序需要另一个声明。

例如,client_1应该具有声明为is_admin的访问令牌,而client_2应该具有声明为stores的访问令牌。

我想知道-以这种方式在访问令牌中添加此类信息是否正常,还是有更好的选择?

如果要在令牌中添加此信息-您能否建议如何根据客户区分在IProfileService实现中添加哪个声明?为此目的使用ClientProperties很好吗?

更新:我使用Azure AD作为外部身份提供者,并且用户没有这些声明-我需要从其他来源检索它

1 个答案:

答案 0 :(得分:2)

在您的配置中,添加一个代表客户端应用范围的IdentityResource,例如client_1_scope,包括IdentityClaim is_admin

client_2_scope(包括IdentityClaim stores)执行相同操作。 还允许客户端请求定义的范围(在ClientScopes中添加一条记录)。

在client_1中,像这样请求范围client_1_scope

options.Scope.Add("client_1_scope");

在client_2中是这样的:

options.Scope.Add("client_2_scope");

当用户拥有声明is_adminstores时,声明将仅作为请求范围的一部分包含。

添加此行以确保添加了声明:

options.GetClaimsFromUserInfoEndpoint = true;

在client_1应用程序中,配置可能如下所示:

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

services
    .AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>
        {
            options.SignInScheme = "Cookies";
            options.GetClaimsFromUserInfoEndpoint = true;
            options.ClaimActions.MapAll();

            options.Scope.Add("client_1_scope");

            options.Authority = "";
            options.ClientId = "";
            options.ClientSecret = "";
            options.ResponseType = "code id_token";
        });

信息将保存在cookie中。如果您希望声明是发送到Api的访问令牌的一部分,则应使用Api〜表来配置声明。


如果这些其他来源已经存在,则可以实现IProfileService,在其中可以根据上述范围添加动态声明,因此仍然需要请求范围。

类似的东西:

using IdentityServer4.Models;
using IdentityServer4.Services;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

public class MyProfileService : IProfileService
{
    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        // Include configured claims.
        context.AddRequestedClaims(context.Subject.Claims);

        // The service gets called multipe times. In this case we need
        // the UserInfo endpoint because that's where the scope is defined.
        if (context.Caller == "UserInfoEndpoint")
        {
            // Get the value from somewhere and transform to a list of claims.
            // You can filter by requested scopes
            List<Claim> userClaims = GetUserClaims(context.RequestedResources.IdentityResources);

            if (userClaims.Any())
                context.IssuedClaims.AddRange(userClaims);
        }
    }

    public async Task IsActiveAsync(IsActiveContext context)
    {
        context.IsActive = true;
    }
}

如果要向访问令牌(用于api的)添加声明,则context.Caller为ClaimsProviderAccessToken,应查看context.RequestedResources.ApiResources。

在启动时注册服务:

.AddProfileService<MyProfileService>()

请注意,这仅是示例。我没有测试代码。


有单独的资料来源,您也可以查看PolicyServer。在这种情况下,您可以保留IdentityServer进行身份验证,保留PolicyServer进行“选择加入”授权。