Как защитить конечные точки на API-ресурсе на основе клиента в identityserver - PullRequest
0 голосов
/ 31 октября 2019

У меня есть собственный сервер авторизации, построенный поверх identityserver4 , где я хочу защитить все apis на хосте. Система представляет собой простую имитацию разработчиков Google или разработчиков Facebook, где владельцы приложений регистрируются и получают идентификатор клиента и секреты клиента для предоставления доступа на apis.

Поэтому я следовал за client_credentials на примере identityserver4,Все работает нормально. Я создал общедоступный пользовательский интерфейс для владельцев приложений, чтобы создавать приложения и выбирать, к какому API обращаться из их приложений. Я использую IConfigurationDbContext для процедур CRUD во внутренних таблицах identityserver.

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

Запуск сервера авторизации

services.AddIdentityServer()
              .AddDeveloperSigningCredential()
              .AddInMemoryCaching()
              .AddOperationalStore(storeOpitons =>
              {
    storeOpitons.ConfigureDbContext = builder =>
      builder.UseSqlServer(Configuration.GetConnectionString("Default"),
      sql => sql.MigrationsAssembly(migrationsAssembly));
})
              .AddConfigurationStore(storeOptions =>
              {
    storeOptions.ConfigureDbContext = builder =>
      builder.UseSqlServer(Configuration.GetConnectionString("Default"),
      sql => sql.MigrationsAssembly(migrationsAssembly));
});

Метод сохранения клиента

public IActionResult SaveApp(ClientViewModel model, List<SelectedApi> selectedApis)
{
    //ommited for brevity

    Client client = new Client
    {
        Description = model.Description,
        ClientName = model.Name,
        RedirectUris = new[] { model.CallBackUri }
    };
    client.AllowedScopes = selectedApis.Where(a => a.apiValue == "true").Select(a => a.apiName).ToList();
    //e.g : client.AllowedScopes = {"employee_api"};

    _isRepository.SaveClient(client, userApp);

}

Api Project Startup

services.AddAuthentication("Bearer").AddJwtBearer(opt => {
    opt.Authority = "http://localhost:5000";
    opt.Audience = "employee_api";
    opt.RequireHttpsMetadata = false;

});

Api Sample Controller

[Authorize]
[Route("api/[controller]")]
[ApiController]
public class EmployeeController : BaseController
{
    private readonly IEmployeeRepository _employeeRepoistory;

    public EmployeeController(IServiceProvider provider, IEmployeeRepository employeeRepository) : base(provider)
    {
        _employeeRepoistory = employeeRepository;

    }
    [HttpGet]
    public IActionResult GetEmployees([FromQuery] EmployeeResourceParameter parameter)
    {
        return Ok(_mapper.Map<IEnumerable<EmployeeModel>>(_employeeRepoistory.GetAll(parameter)));
    }
    [HttpGet("{id:int}")]
    public IActionResult GetEmployeeById(int id)
    {
        var emp = _employeeRepoistory.GetById(id);

        return Ok(_mapper.Map<EmployeeModel>(emp));

    }
}

Что мне нужно, если разработчик выберет employee_api, он должен просто достичьв оконечные точки EmployeeController. Однако, прямо сейчас, они могут достичь всех apis, независимо от того, какой у них выбор. Какие шаги нужно предпринять для этого на стороне API или на стороне сервера аутентификации?

enter image description here

1 Ответ

0 голосов
/ 31 октября 2019

Наконец-то я это сделал .. Прежде всего, я понял, что важно понять связь между ApiResource -> Scopes, Clients -> AllowedScopes. Я предлагаю вам прочитать части о них в документах и здесь

Когда клиент зарегистрирован на identityserver, а затем выбрать конечные точки API ( например: организация, сотрудник, календарь ) они должны быть зарегистрированы как разрешенные. Области клиента ( они живут в таблице ClientScopes ), я делал это правильно. То, что я делал неправильно, я предполагаю, что все эти области являются ApiResources ( для моего случая, потому что все мои apis живут на том же хосте, который я называю CommonServiceApi, только одно приложение веб-API ). Я переопределил свои ApiResources и его области следующим образом:

new ApiResource("commonserviceapi", "Common Service API")
{
    Scopes = {
        new Scope("calender_api", "Calender Api"),
        new Scope("employee_api", "Employee Api"),
        new Scope("organization_api", "Organization Api"),
    }
}

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

Итак, Api Запуск

services.AddAuthentication("Bearer").AddJwtBearer(opt =>
            {
    opt.Authority = "http://localhost:5000";
    opt.Audience = "commonserviceapi";

    opt.RequireHttpsMetadata = false;

});

services.AddAuthorization(options =>
{
    options.AddPolicy("ApiEmployee", builder =>
    {
        builder.RequireScope("employee_api");
    });
    options.AddPolicy("ApiOrganization", builder =>
    {
        builder.RequireScope("organization_api");
    });
});

И Api Контроллеры

[Authorize(Policy = "ApiEmployee")]
[Route("api/[controller]")]
[ApiController]
public class EmployeeController : BaseController
{
    ...

RequireScope - это, кстати, метод расширения пакета IdentityServer4.AccessTokenValidation. Вы должны включить этот пакет в свой проект API.

И, наконец, это меня смутило;при запросе токена доступа с сервера параметр области должен быть пустым , так как identityserver берет его из значений allowdScopes клиента. Почти все образцы заполняли это поле, поэтому можно подумать, что оно должно быть заполнено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...