Реализовать одну общую службу авторизации, которая должна вызываться, когда я добавляю к ней атрибут авторизации в нескольких приложениях / API

#identityserver4 #identity #policy-server

#identityserver4 #идентификация #политика-сервер

Вопрос:

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

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

IdentityServer — это не вариант, в то время как мои разрешения не могут быть сохранены в виде утверждений из-за размера токена. В нее входит около 200 повторных операций, поэтому это должно быть сделано в dbcontext или что-то в этом роде.

Я посмотрел на PolicyServer, но он работал не так, как я ожидал. Когда я установил ее в приложении IS4, она работает на контроллерах IS4, но когда Authorize вызывается из внешнего приложения, она вообще не вызывает переопределение Authorize, поскольку она должна проверять разрешения. И кажется, что разрешения не установлены во внешнем приложении ни в User.Claims, ни в чем другом. Я думаю, что мне не хватает некоторых настроек.

Чего я хочу добиться, так это того, чтобы у меня было одно хранилище разрешений (таблица) (которое, например, содержит кучу кнопок индексирования, добавления, редактирования или удаления или что-то еще). Он должен быть предоставлен аутентифицированному пользователю, который вошел в систему. Но это единственное хранилище данных должно быть доступно во всех приложениях или API, которые я запускаю, чтобы атрибут Authorize мог выполнять свою работу.

Я думаю, что это не должно быть так сложно сделать, поэтому мне не хватает хорошего рабочего примера, как реализовать что-то подобное и что работает. Кто может мне помочь с этим, чтобы это было сделано?

Я написал некоторый код для получения разрешений с помощью вызова API и использования его в переопределении IsInRole. Но когда я объявляю ее с помощью Authorize attr, она не будет получена в методе:

 [ApiController]
1) [Authorize]
public class AuthController : ControllerBase
{
private readonly IdentityContext _context;
public AuthController(IdentityContext context)
{
   _context = context ?? throw new Ar&umentNullException(nameof(context));
}

[HttpGet()]
[Route("api/auth/isinrole")]
public bool IsInRole(strin& role)
{
2) if (User.FindFirst("sub")?.Value != null)
   {
      var userID = Guid.Parse(User.FindFirst("sub")?.Value);
      if([This is the code that checks if user has role])
         return true;
   }
   return false;
  

Это переопределение IsInRole (ClaimsPrincipal.Переопределение IsInRole):

 public override bool IsInRole(strin& role)
{
    var httpClient = _httpClientFactory.CreateClient("AuthClient");
3)  var accessToken = _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken).Resu< 

    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
    var request = new HttpRequestMessa&e(HttpMethod.Get, "/api/auth/isinrole/?id="   role);
    var response = httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Resu<

etc...

  
  1. Это не работает, пока она не отправляет access_token в запросе
  2. ‘sub’ не отправляется
  3. Всегда равно null

Ответ №1:

Версия PolicyServer с открытым исходным кодом является локальной реализацией. Все, что она делает, это считывает разрешения из хранилища (в примере файла конфигурации a) и преобразует их в утверждения с использованием промежуточного программного обеспечения.

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

Имея локальные разрешения, у вас не может быть конфликтов с другими ресурсами. Например. быть администратором в api1 не означает, что вы являетесь администратором и в api2.

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

Для этого вам нужно будет добавить дискриминатор, чтобы различать ресурсы. Я использую области, потому что это единственное, что совместно используется как клиентом, так и ресурсом.

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

Альтернативой является использование IdentityServer как есть. Но вместо токенов JWT используйте ссылочные токены.

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

Комментарии:

1. Привет, tnx за твой ответ. Можете ли вы привести мне несколько примеров кода, как реализовать всю эту вашу идею? Я полагаю, что я каким-либо образом не ограничен никакими ограничениями, потому что утверждения ограничены по размеру. В моем случае пользователь может иметь, скажем, 250 разрешений.

2. Файлы cookie и заголовки ограничены по размеру, а не утверждения или токены. Их обход снимет ограничения. У меня нет для вас кода, но я уверен, что вы можете написать конечную точку авторизации пользователя, которая возвращает разрешения, являющиеся частью области видимости. Для клиентов / ресурсов вы можете использовать пример кода из OSS-версии PolicyServer, где файл конфигурации json заменяется вызовом HttpClient к конечной точке сервера, запрашивающим разрешения только для разрешенных областей. Используйте локальный кэш для повышения производительности.

3. Я думаю, вы имеете в виду создать метод API, который возвращает, если у пользователя есть разрешение. А затем вызываю этот API в ClaimsPrincipal. Переопределение IsInRole с помощью HttpClient. Правильно?

4. Конечная точка — это метод API, но переопределение предшествует IsInRole. Глядя на исходный код, вы можете настроить код для чтения утверждений из вашего собственного хранилища, например, var claims = await authStore.GetClaimsAsync(); где хранилище инициализирует HttpClient и выполняет фактический вызов API. В следующих строках утверждения добавляются в коллекцию нового удостоверения, которое добавляется к участнику утверждений, источнику политик и IsInRole.

5. Привет, я думаю, что ищу что-то, что проще для понимания. Я новичок в этом вопросе безопасности / идентификации / токена. Я учусь на рабочих примерах, предпочитаю голландский. Итак, я добавил некоторый код в вопрос, который я использую сейчас. Но пока не работает, потому что токены аутентификации не отправляются с запросом. Я чего-то не понимаю.

Ответ №2:

Существует альтернатива вашему решению, и она заключается в использовании ссылочного токена вместо JWT-токена. Ссылочный токен — это просто непрозрачный идентификатор, и когда клиент получает этот токен, он должен перейти и посмотреть реальный токен и детали через серверную часть. Ссылочный токен не содержит никакой информации. Это просто идентификатор поиска, который клиент может использовать против IdentiyServer

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

Использование ссылочного токена — это всего лишь один из доступных вам вариантов.

смотрите документацию о ссылочных токенах

Комментарии:

1. Вы имеете в виду ссылочный токен ?

2. Да! Я исправлю свой ответ