如何在没有“主题”字段的情况下以JSON格式获取声明?

xurqigkl  于 2023-04-22  发布在  其他
关注(0)|答案(1)|浏览(120)

我在一个基本的Web API中使用System.Security.Claims和JWT令牌,因此在我的program.cs中定义了一个.AddAuthentication().AddJwtBearer()和一些登录方法。这一切都很好。但是现在我需要一个特定的声明保存为JSON并返回给客户端。这是一个名为“Host”的自定义声明,它只是请求发出的主机名。
我使用这段代码基本上将任何对象转换为JSON:

public static class JSonHelpers
{
    public static JsonSerializerSettings NoLoop = new() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
    
    public static string SaveAsJson<T>(this T data, Formatting format = Formatting.Indented, JsonSerializerSettings? settings = null)
    {
        try { return JsonConvert.SerializeObject(data, format, settings); }
        catch (Exception ex) { return ex.Message; }
    }
}

上面的代码基本上为每个对象提供了一个额外的方法来从它的内容生成JSON字符串。它也有一些简单的错误处理,因为如果有错误,它将返回异常作为字符串。不漂亮,但客户端将处理任何这些错误。
我的控制器有这个方法:

[HttpGet("host")]
    [Authorize]
    [SwaggerResponse(StatusCodes.Status200OK)]
    [SwaggerResponse(StatusCodes.Status401Unauthorized)]
    [Produces(MediaTypeNames.Text.Plain)]
    public string HostClaim()
    {
        return User.Claims.Where(c=>c.Type=="Host").ToList().SaveAsJson(settings: JSonHelpers.NoLoop);
    }

实际上,这是一个非常简单的方法。它返回一个数组,因为“where”过滤器将在将来进行调整,以返回多个声明。
你必须被授权调用它,这意味着你也有主机声明。
我现在要你把所有的东西都退回去,不要那些"主题"的东西.
因为我得到了这个JSON内容:

{
    "Issuer": "Katje",
    "OriginalIssuer": "Katje",
    "Properties": {},
    "Subject": {
      "AuthenticationType": "AuthenticationTypes.Federation",
      "IsAuthenticated": true,
      "Actor": null,
      "BootstrapContext": null,
      "Claims": [
        {
          "Issuer": "Katje",
          "OriginalIssuer": "Katje",
          "Properties": {},
          "Type": "User",
          "Value": "boss",
          "ValueType": "http://www.w3.org/2001/XMLSchema#string"
        },
        <<<< Lots more claims >>>>
        <<<< Lots more claims >>>>
        <<<< Lots more claims >>>>
        {             
          "Issuer": "Katje",
          "OriginalIssuer": "Katje",
          "Properties": {},
          "Type": "aud",
          "Value": "Everyone",
          "ValueType": "http://www.w3.org/2001/XMLSchema#string"
        }
      ],
      "Label": null,
      "Name": null,
      "NameClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
      "RoleClaimType": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
    },
    "Type": "Host",
    "Value": "localhost",
    "ValueType": "http://www.w3.org/2001/XMLSchema#string"
}

这比我需要的要多得多!这是因为“Subject”指向所有声明的列表,所以当我只需要一个声明时,我可以得到所有声明。我可以创建一个自定义的匿名类,除了Subject之外的所有字段。这也不是很漂亮。但是这样做:

return User.Claims.Where(c => c.Type == "Host").Select(r => new { r.Issuer, r.OriginalIssuer, r.Properties, r.Type, r.Value, r.ValueType }).ToList().SaveAsJson(settings: JSonHelpers.NoLoop);

这样就可以了。但是我的问题是我必须创建一个新的匿名对象并包含我想要的数据。

  • 是否可以排除我不想要的字段?*
fnvucqvd

fnvucqvd1#

这样就可以了。但是我的问题是我必须创建一个新的匿名对象并包含我想要的数据。
这就是跨边界发送数据时的要点。您创建(匿名)DTO,以便控制序列化的内容和方式。
如果你不想这样,你可以克隆Claims示例,文档如下:
返回从该对象复制的新声明对象。新声明没有主题。
所以:

var hostClaim = User.Claims.Where(c => c.Type == "Host")
    .Select(c => c.Clone())
    .ToList()
    .SaveAsJson(settings: JSonHelpers.NoLoop);

相关问题