Browse Source

Add authorization support with policies and roles in API description models

pull/24870/head
maliming 4 months ago
parent
commit
fa492e027d
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 17
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs
  2. 6
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs
  3. 8
      framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/AuthorizeDataApiDescriptionModel.cs
  4. 66
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController_Tests.cs
  5. 4
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPeopleAppService.cs
  6. 13
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs

17
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs

@ -121,19 +121,20 @@ public class AspNetCoreApiDescriptionModelProvider : IApiDescriptionModelProvide
Logger.LogDebug($"ActionApiDescriptionModel.Create: {controllerModel.ControllerName}.{uniqueMethodName}");
bool? allowAnonymous = null;
string? requiredPolicy = null;
var authorizeModels = new List<AuthorizeDataApiDescriptionModel>();
if (apiDescription.ActionDescriptor.EndpointMetadata.Any(x => x is IAllowAnonymous))
{
allowAnonymous = true;
}
else
else if (apiDescription.ActionDescriptor.EndpointMetadata.Any(x => x is IAuthorizeData))
{
var authorizeData = apiDescription.ActionDescriptor.EndpointMetadata.FirstOrDefault(x => x is IAuthorizeData);
if (authorizeData != null)
allowAnonymous = false;
var authorizeDatas = apiDescription.ActionDescriptor.EndpointMetadata.Where(x => x is IAuthorizeData).Cast<IAuthorizeData>().ToList();
authorizeModels.AddRange(authorizeDatas.Select(authorizeData => new AuthorizeDataApiDescriptionModel
{
allowAnonymous = false;
requiredPolicy = (authorizeData as IAuthorizeData)?.Policy;
}
Policy = authorizeData.Policy,
Roles = authorizeData.Roles
}));
}
var implementFrom = controllerType.FullName;
@ -153,7 +154,7 @@ public class AspNetCoreApiDescriptionModelProvider : IApiDescriptionModelProvide
apiDescription.HttpMethod,
GetSupportedVersions(controllerType, method, setting),
allowAnonymous,
requiredPolicy,
authorizeModels,
implementFrom
)
);

6
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs

@ -28,7 +28,7 @@ public class ActionApiDescriptionModel
public bool? AllowAnonymous { get; set; }
public string? RequiredPolicy { get; set; }
public IList<AuthorizeDataApiDescriptionModel> AuthorizeDatas { get; set; } = default!;
public string? ImplementFrom { get; set; }
@ -37,7 +37,7 @@ public class ActionApiDescriptionModel
}
public static ActionApiDescriptionModel Create([NotNull] string uniqueName, [NotNull] MethodInfo method, [NotNull] string url, string? httpMethod, [NotNull] IList<string> supportedVersions, bool? allowAnonymous = null, string? requiredPolicy = null, string? implementFrom = null)
public static ActionApiDescriptionModel Create([NotNull] string uniqueName, [NotNull] MethodInfo method, [NotNull] string url, string? httpMethod, [NotNull] IList<string> supportedVersions, bool? allowAnonymous = null, IList<AuthorizeDataApiDescriptionModel>? authorizeDatas = null, string? implementFrom = null)
{
Check.NotNull(uniqueName, nameof(uniqueName));
Check.NotNull(method, nameof(method));
@ -58,7 +58,7 @@ public class ActionApiDescriptionModel
.ToList(),
SupportedVersions = supportedVersions,
AllowAnonymous = allowAnonymous,
RequiredPolicy = requiredPolicy,
AuthorizeDatas = authorizeDatas ?? new List<AuthorizeDataApiDescriptionModel>(),
ImplementFrom = implementFrom
};
}

8
framework/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/AuthorizeDataApiDescriptionModel.cs

@ -0,0 +1,8 @@
namespace Volo.Abp.Http.Modeling;
public class AuthorizeDataApiDescriptionModel
{
public string? Policy { get; set; }
public string? Roles { get; set; }
}

66
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController_Tests.cs

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Http.Modeling;
@ -23,4 +24,67 @@ public class AbpApiDefinitionController_Tests : AspNetCoreMvcTestBase
model.ShouldNotBeNull();
model.Types.IsNullOrEmpty().ShouldBeFalse();
}
[Fact]
public async Task Should_Have_Null_AllowAnonymous_For_Actions_Without_Authorization()
{
var model = await GetResponseAsObjectAsync<ApplicationApiDescriptionModel>("/api/abp/api-definition");
var peopleController = GetPeopleController(model);
var action = GetAction(peopleController, "GetPhones");
action.AllowAnonymous.ShouldBeNull();
action.AuthorizeDatas.ShouldBeEmpty();
}
[Fact]
public async Task Should_Set_AllowAnonymous_True_For_AllowAnonymous_Actions()
{
var model = await GetResponseAsObjectAsync<ApplicationApiDescriptionModel>("/api/abp/api-definition");
var peopleController = GetPeopleController(model);
var action = GetAction(peopleController, "GetWithAllowAnonymous");
action.AllowAnonymous.ShouldBe(true);
action.AuthorizeDatas.ShouldBeEmpty();
}
[Fact]
public async Task Should_Set_AllowAnonymous_False_And_AuthorizeDatas_For_Authorize_Actions()
{
var model = await GetResponseAsObjectAsync<ApplicationApiDescriptionModel>("/api/abp/api-definition");
var peopleController = GetPeopleController(model);
var action = GetAction(peopleController, "GetWithAuthorized");
action.AllowAnonymous.ShouldBe(false);
action.AuthorizeDatas.ShouldNotBeEmpty();
}
[Fact]
public async Task Should_Contain_Policy_And_Roles_In_AuthorizeDatas()
{
var model = await GetResponseAsObjectAsync<ApplicationApiDescriptionModel>("/api/abp/api-definition");
var peopleController = GetPeopleController(model);
var action = GetAction(peopleController, "GetWithAuthorizePolicy");
action.AllowAnonymous.ShouldBe(false);
action.AuthorizeDatas.Count.ShouldBe(2);
action.AuthorizeDatas.ShouldContain(a => a.Policy == "TestPolicy" && a.Roles == "Admin");
action.AuthorizeDatas.ShouldContain(a => a.Policy == "TestPolicy2" && a.Roles == "Manager");
}
private static ControllerApiDescriptionModel GetPeopleController(ApplicationApiDescriptionModel model)
{
return model.Modules.Values
.SelectMany(m => m.Controllers.Values)
.First(c => c.ControllerName == "People");
}
private static ActionApiDescriptionModel GetAction(ControllerApiDescriptionModel controller, string actionName)
{
return controller.Actions.Values
.First(a => a.Name == actionName + "Async" || a.Name == actionName);
}
}

4
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPeopleAppService.cs

@ -20,6 +20,10 @@ public interface IPeopleAppService : ICrudAppService<PersonDto, Guid>
Task GetWithAuthorized();
Task GetWithAllowAnonymous();
Task GetWithAuthorizePolicy();
Task<GetWithComplexTypeInput> GetWithComplexType(GetWithComplexTypeInput input);
Task<IRemoteStreamContent> DownloadAsync();

13
framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs

@ -67,6 +67,19 @@ public class PeopleAppService : CrudAppService<Person, PersonDto, Guid>, IPeople
return Task.CompletedTask;
}
[AllowAnonymous]
public Task GetWithAllowAnonymous()
{
return Task.CompletedTask;
}
[Authorize("TestPolicy", Roles = "Admin")]
[Authorize("TestPolicy2", Roles = "Manager")]
public Task GetWithAuthorizePolicy()
{
return Task.CompletedTask;
}
public Task<GetWithComplexTypeInput> GetWithComplexType(GetWithComplexTypeInput input)
{
return Task.FromResult(input);

Loading…
Cancel
Save