Благодаря этому сообщению: Перечисление всех развернутых конечных точек отдыха (spring-boot, jersey)
В частности, пост Иоганна Джандера (спасибо!), Я пришел к следующемукод, который, кажется, работает в моем случае, простой случай использования Джерси.Предоставляя его здесь на случай, если это будет полезно для других.
@Path("/v1/userinterface")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class MyUI extends MyRestApi {
private final static Logger log = LoggerFactory.getLogger(MyUI.class);
@Context
private Configuration configuration;
@Context
private SecurityContext security;
@Path("/allowedendpoints")
@GET
@Operation(summary = "List API access points allowed for the currently authenticated user", tags = {
"ui" }, description = "Returns a list of urls", responses = {})
public Response showAll(@Context UriInfo ui) {
log.debug("Get list of all allowed endpoints for user: " + security.getUserPrincipal().getName());
HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
for (Class<?> c : configuration.getClasses()) {
// Since all of my endpoint classes extend MyRestApi,
// only scan them, not all classes
if (MyRestApi.class.isAssignableFrom(c)) {
scanClass(c, map);
}
}
return Response.ok().entity(map).build();
}
public void scanClass(Class<?> baseClass, HashMap<String, ArrayList<String>> map) {
Builder builder = Resource.builder(baseClass);
if (null != builder) {
Resource resource = builder.build();
String uriPrefix = "";
process(uriPrefix, resource, map);
}
}
private void process(String uriPrefix, Resource resource, HashMap<String, ArrayList<String>> map) {
// recursive method
String pathPrefix = uriPrefix;
List<Resource> resources = new ArrayList<>();
resources.addAll(resource.getChildResources());
if (resource.getPath() != null) {
pathPrefix = (pathPrefix + "/" + resource.getPath()).replaceAll("//", "/");
}
for (ResourceMethod method : resource.getAllMethods()) {
if (method.getType().equals(ResourceMethod.JaxrsType.SUB_RESOURCE_LOCATOR)) {
resources.add(Resource
.from(resource.getResourceLocator().getInvocable().getDefinitionMethod().getReturnType()));
} else {
if (isPathAllowed(security, method.getInvocable().getDefinitionMethod())) {
if (map.containsKey(pathPrefix))
map.get(pathPrefix).add(method.getHttpMethod());
else
map.put(pathPrefix, new ArrayList<String>(Arrays.asList(method.getHttpMethod())));
}
}
}
for (Resource childResource : resources) {
process(pathPrefix, childResource, map);
}
}
public boolean isPathAllowed(SecurityContext ctx, Method method) {
// @DenyAll on the method takes precedence over @RolesAllowed and @PermitAll
if (method.isAnnotationPresent(DenyAll.class)) {
return (false);
}
// @RolesAllowed on the method takes precedence over @PermitAll
RolesAllowed rolesAllowed = method.getAnnotation(RolesAllowed.class);
if (rolesAllowed != null) {
return (hasRole(ctx, rolesAllowed.value()));
}
// @PermitAll on the method takes precedence over @RolesAllowed on the class
if (method.isAnnotationPresent(PermitAll.class)) {
return (true);
}
// @DenyAll can't be attached to classes
// @RolesAllowed on the class takes precedence over @PermitAll on the class
rolesAllowed = method.getDeclaringClass().getAnnotation(RolesAllowed.class);
if (rolesAllowed != null) {
return (hasRole(ctx, rolesAllowed.value()));
}
// @PermitAll on the class
if (method.getDeclaringClass().isAnnotationPresent(PermitAll.class)) {
return (true);
}
return (false); // default
}
private boolean hasRole(SecurityContext ctx, String[] rolesAllowed) {
for (final String role : rolesAllowed) {
if (ctx.isUserInRole(role)) {
return (true);
}
}
return (false);
}
Возвращает конечные точки, к которым имеет доступ текущий аутентифицированный пользователь, на основе разметки SecurityContext с аннотациями @DenyAll, @PermitAll и @RolesAllowed.
Полное раскрытие, мое приложение просто с простыми аннотациями классов и методов на конечных точках.мммм.
Пример вывода:
{
"/v1/resources" : [
"POST",
"GET"
],
"/v1/resources/{id}" : [
"DELETE",
"GET"
]
}