Добавить заявку в JWT в виде массива?

Используя поток владельца ресурса проверки подлинности thinktecture JWT, я использую часть утверждений JWT для потребления клиентом. Мой вопрос заключается в том, возможно ли добавить требование на сервер идентификации и декодировать его как массив в клиенте.

Нет ClaimTypeValues ​​для типа массива.

Как обходной путь,

 var user = IdentityServerPrincipal.Create(response.UserName, response.UserName);
                user.Identities.First().AddClaims(
                                            new List<Claim>()
                                        {
                                            new Claim(ClaimTypes.Name, response.UserName),
                                            new Claim(ClaimTypes.Email, response.Email),
                                            new Claim(FullName, response.FullName),
                                            new Claim(AuthorizedCompanies,JsonConvert.SerializeObject(response.AuthorizedCompanies))
                                        });
                return new AuthenticateResult(user);

Я добавляю запрос в виде массива json для запроса AuthorizedCompanies и анализирую его на стороне клиента. Каков здесь шаблон проектирования, если он есть?


person sercan    schedule 03.12.2014    source источник


Ответы (4)


Исходя из личного опыта, легче взаимодействовать с хранилищами утверждений, когда ValueType всегда имеет тип «String». Хотя это может показаться нелогичным, когда вы знаете, что имеете дело со сложным типом, это, по крайней мере, просто для понимания.

Способ, которым я подошел к этой потребности в массиве, состоит в том, чтобы код моего приложения ожидал присутствия нескольких утверждений для рассматриваемого типа утверждения и сохранял значение каждого утверждения простого типа.

Пример:

var authorizeCompanies = identity.FindAll(AuthorizedCompanies).Select(c => c.Value);

И, конечно же, вы также добавляете их таким образом:

identity.AddClaim(ClaimTypes.Name, response.UserName);
identity.AddClaim(AuthorizedCompanies, "CompanyX");
identity.AddClaim(AuthorizedCompanies, "CompanyY");
identity.AddClaim(AuthorizedCompanies, "CompanyZ");

IdentityServer поддерживает эту модель «из коробки». При создании токена для такого удостоверения он автоматически записывает значения для этого утверждения в виде массива.

{
    "aud": "Identity Server example/resources", 
    "iss": "Identity Server example", 
    "exp": 1417718816, 
    "sub": "1234",
    "scope": ["read", "write"], // <-- HERE
    "foo": ["bar", "baz"],      // <-- HERE TOO!
    "nbf": 1417632416
}

Этот подход к утверждениям отличается от предположения, что все утверждения представляют собой однозначное сопоставление типа -> значение.

person Crescent Fresh    schedule 03.12.2014
comment
Если у вас есть только одна компания company, вы получите не массив, а простую строку в утверждении AuthorizedCompanies. Но если у вас их несколько, вы получите массив строк. Это правильно? - person gajo357; 03.07.2020
comment
Я думал сделать что-то подобное, но потом обнаружил в спецификации JWT следующее: Имена утверждений в наборе утверждений JWT ДОЛЖНЫ быть уникальными; Парсеры JWT ДОЛЖНЫ либо отклонять JWT с повторяющимися именами утверждений, либо использовать парсер JSON, который возвращает только лексически последнее повторяющееся имя члена (tools.ietf.org/html/rfc7519 в разделе 4) - person FercoCQ; 17.10.2020
comment
@FercoCQ Я думаю, что IS возвращает одно имя претензии со значением массива, закодированного в json, и, следовательно, это не нарушает определение rfc. - person Vočko; 27.10.2020
comment
@Vočko действительно ... Я смотрел на проблему со стороны .Net, но я считаю, что код, который фактически создает JWT, должен преобразовывать несколько утверждений одного типа в массив, чтобы соответствовать спецификации. - person FercoCQ; 27.10.2020
comment
Обратите внимание, что JWT OAuth Спецификация маркера доступа говорит, что область должна быть отформатирована, как описано в RFC8693, который представляет собой список с разделителями-пробелами, а не массив, поэтому, хотя вы МОЖЕТЕ сделать это, вы не должны делать это для области. - person Chris D; 14.01.2021

У меня была аналогичная проблема, в моем случае у меня есть утверждения, которые являются массивами, но иногда имеют только один элемент в зависимости от разрешений пользователя. В этом случае, если вы используете new Claim("key", "value") для их добавления, они будут строками, когда есть один объект и массивы, когда> 1, что было неприемлемо.

Лучшим решением в этом случае является использование JwtPayload для создания объекта JwtSecurityToken.

var payload = new JwtPayload
    {
        { "ver", version },
        { "iss", "example.com"},
        { "iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds()},
        { "exp", DateTimeOffset.UtcNow.AddHours(1).ToUnixTimeSeconds()},
        { "aud", myExampleStringList }
    };
var token = new JwtSecurityToken(new JwtHeader(_signingCredentials), payload);

Это работает на .netcore 3.0 с использованием System.IdentityModel.Tokens.Jwt v3.0, но я не могу подтвердить для других версий.

person WillDoDatDevDoe    schedule 24.10.2019

использовать JsonClaimValueTypes в качестве типа утверждения

var tokenDescriptor = new SecurityTokenDescriptor
   {
    Subject = new ClaimsIdentity(new Claim[]
     { new Claim("listName", list != null ? JsonSerializer.Serialize(user.RoleName) : string.Empty,JsonClaimValueTypes.JsonArray)
    }}
person shahabas sageer    schedule 09.06.2020

Identity Server преобразует значение из массива в строку, если вы хотите добавить одно значение в массив. Более простым решением было бы преобразовать массив как json и добавить к заявке с valueType как json.

IList<string> companies = new List<string>();
companies.Add("CompanyA");
string companiesJson = JsonConvert.SerializeObject(companies);
context.IssuedClaims.Add(new Claim("Companies", companiesJson, IdentityServerConstants.ClaimValueTypes.Json));

Приведенное выше решение позволит вам добавить одно или несколько значений в качестве массива.

person Abhishek Dhotre    schedule 20.03.2020