炫耀 + 弹簧安全 - 隐藏基于角色的方法

我有一个具有不同使用者的 API。我希望他们根据他们在Spring Security中的角色获得相关文档。

例如

API 操作 A 被限制为角色 A 和角色 B

API 操作 B 被限制为角色 B

API 操作 C 对所有人开放

我正在使用SpringFox,Spring 4,Spring Rest,Security

我知道有一个叫做 的注释,也许可以利用。@ApiIgnore

这有可能吗?


答案 1

经过一番搜索,我发现在网络中没有办法解决这个问题。所以我用自己的解决方案解决了它。

我编写了一个过滤器,用于修改响应并删除用户无权访问它们的api。

过滤器如下所示:

 @Override
 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpServletRequest = (HttpServletRequest) request;
    String url = httpServletRequest.getRequestURI();
        if (url.contains("v2/api-docs")) {
            CharResponseWrapper wrapper = new CharResponseWrapper((HttpServletResponse) response);
            chain.doFilter(httpServletRequest, wrapper);
            refineApiBaseOnACL(wrapper);
            return;
        }
    chain.doFilter(httpServletRequest, response);
}

要修改响应,您应该点击此链接

然后,我们需要优化生成的 api:

private List<String> httpCommands = List.of("get", "head", "post", "put", "delete", "options", "patch");

public void refineApiBaseOnACL(CharResponseWrapper wrapper) {
    try {
        byte[] bytes = wrapper.getByteArray();

        if (wrapper.getContentType().contains("application/json")) {
            String out = refineContentBaseOnACL(new String(bytes));
            wrapper.getResponse().getOutputStream().write(out.getBytes());
        } else {
            wrapper.getResponse().getOutputStream().write(bytes);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private String refineContentBaseOnACL(String originalContent) {
    JSONObject object = new JSONObject(originalContent);
    JSONObject paths = object.getJSONObject("paths");
    JSONArray tags = object.getJSONArray("tags");

    Iterator keys = paths.keys();
    Set<String> toRemovePath = new HashSet<>();
    Set<Integer> toRemoveTags = new HashSet<>();
    Set<String> tagSet = new HashSet<>();
    while (keys.hasNext()) {
        String key = (String) keys.next();
        String[] split = key.split("/");
        if (!getAccessHandler().checkAccessRest(split[1], split[2]))
            toRemovePath.add(key);
        else {
            for (String httpCommand : httpCommands)
                if (paths.getJSONObject(key).has(httpCommand)) {
                    JSONObject command = paths.getJSONObject(key).getJSONObject(httpCommand);
                    JSONArray tagsArray = command.getJSONArray("tags");
                    for (int i = 0; i < tagsArray.length(); i++)
                        tagSet.add(tagsArray.getString(i));
                }
        }
    }

    for (String key : toRemovePath)
        paths.remove(key);

    for (int i = 0; i < tags.length(); i++)
        if (!tagSet.contains(tags.getJSONObject(i).getString("name")))
            toRemoveTags.add(i);

    List<Integer> sortedTags = new ArrayList<>(toRemoveTags);
    sortedTags.sort(Collections.reverseOrder());
    for (Integer key : sortedTags)
        tags.remove(key);


    Pattern modelPattern = Pattern.compile("\"#/definitions/(.*?)\"");
    Set<String> modelSet = new HashSet<>();
    Matcher matcher = modelPattern.matcher(object.toString());
    while (matcher.find())
        modelSet.add(matcher.group(1));

    JSONObject definitions = object.getJSONObject("definitions");
    Set<String> toRemoveModel = new HashSet<>();
    Iterator definitionModel = definitions.keys();
    while (definitionModel.hasNext()) {
        String definition = (String) definitionModel.next();
        boolean found = false;
        for (String model : modelSet)
            if (definition.equals(model)) {
                found = true;
                break;
            }
        if (!found)
            toRemoveModel.add(definition);
    }

    for (String model : toRemoveModel) {
        definitions.remove(model);
    }

    return object.toString();
}

在我的情况下,我有一个用url处理访问控制的方法。您应该在逻辑上编写此部分。对于 spring 安全角色,您可以使用如下方法:AccessHandler

request.isUserInRole("Role_A");

答案 2

我已经发布了类似的问题,并在一点点找到了解决方案。由于我在stackoverflow上发现了3个类似的问题,我不知道我是否应该在所有问题中复制粘贴答案,或者提供指向我的答案的链接。

解决方案由两部分组成:

  1. 扩展控制器扫描逻辑,以保留 Swagger 供应商扩展中的角色OperationBuilderPlugin
  2. 覆盖 Bean 以根据当前安全上下文筛选出操作ServiceModelToSwagger2MapperImpl

详细信息可以在这里找到:https://stackoverflow.com/a/61860729/285060


推荐