如何根据身份服务器中的客户端保护 api 资源上的端点
How to secure endpoints on api resource based on client in identityserver
我在 identityserver4 上构建了自己的授权服务器,我想在其中保护主机上的所有 api .系统只是 google 开发人员或 facebook 开发人员的简单模仿,其中应用程序所有者注册并获取客户端 ID 和客户端机密以在 api 上授予访问权限。
所以我按照 client_credentials 流在 identityserver4 样本上。一切正常。我为应用程序所有者构建了一个 public UI 来创建应用程序并选择要从他们的应用程序访问的 apis。我在 identityserver 的内部表上使用 IConfigurationDbContext
进行 CRUD 处理。
问题是我找不到根据应用程序所有者的选择来保护 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 项目启动
services.AddAuthentication("Bearer").AddJwtBearer(opt => {
opt.Authority = "http://localhost:5000";
opt.Audience = "employee_api";
opt.RequireHttpsMetadata = false;
});
Api 样本控制器
[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 的端点。但是现在,无论他们的选择是什么,他们都可以到达所有 api。
在 api 端或授权服务器端为此采取哪些步骤?
中有关它们的部分
当客户端注册到身份服务器然后选择 api 端点(例如:组织、员工、日历)时,它们应该注册为客户端的允许范围( 他们住在 ClientScopes table),我做的是正确的方式。我做错的是我假设所有这些范围都是 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 端,应使用 here 指示的策略授权端点。
在访问令牌中,请求客户端的 允许范围 被传递给 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 项目中。
最后,这让我很困惑;从服务器请求访问令牌时,范围参数 应该为空 ,因为身份服务器从客户端的 allowdScopes 值中获取它。几乎所有示例都在填充此字段,因此您认为它应该被填充。
我在 identityserver4 上构建了自己的授权服务器,我想在其中保护主机上的所有 api .系统只是 google 开发人员或 facebook 开发人员的简单模仿,其中应用程序所有者注册并获取客户端 ID 和客户端机密以在 api 上授予访问权限。
所以我按照 client_credentials 流在 identityserver4 样本上。一切正常。我为应用程序所有者构建了一个 public UI 来创建应用程序并选择要从他们的应用程序访问的 apis。我在 identityserver 的内部表上使用 IConfigurationDbContext
进行 CRUD 处理。
问题是我找不到根据应用程序所有者的选择来保护 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 项目启动
services.AddAuthentication("Bearer").AddJwtBearer(opt => {
opt.Authority = "http://localhost:5000";
opt.Audience = "employee_api";
opt.RequireHttpsMetadata = false;
});
Api 样本控制器
[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 的端点。但是现在,无论他们的选择是什么,他们都可以到达所有 api。 在 api 端或授权服务器端为此采取哪些步骤?
当客户端注册到身份服务器然后选择 api 端点(例如:组织、员工、日历)时,它们应该注册为客户端的允许范围( 他们住在 ClientScopes table),我做的是正确的方式。我做错的是我假设所有这些范围都是 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 端,应使用 here 指示的策略授权端点。 在访问令牌中,请求客户端的 允许范围 被传递给 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 项目中。
最后,这让我很困惑;从服务器请求访问令牌时,范围参数 应该为空 ,因为身份服务器从客户端的 allowdScopes 值中获取它。几乎所有示例都在填充此字段,因此您认为它应该被填充。