java - 按方法和用户进行 ReSTLet 授权

标签 java authentication authorization restlet

我对 ReSTLet 和 REST 不太熟悉,希望为正在运行的服务器/数据库实现 RESTful API。到目前为止,路由和寻址似乎工作正常,但我需要一些关于如何处理身份验证和授权的提示。

情况:有些资源只有部分用户才能以某些方式进行交互。例如,User1 可能能够 GET 资源,但不能 PUT 任何内容,而 User2 可以同时执行这两种操作,User3 甚至可能无法读取该资源,而 User4 是唯一允许使用 DELETE 的用户。

当然,MethodAuthorizer 听起来很有希望,但它似乎只区分匿名用户和(所有)经过身份验证的用户。另一方面,RoleAuthorizer 不会区分 GET、PUT 或其他请求方法,只会区分资源。

我如何只授权某些用户只执行某些任务?有没有办法组合授权者,或者让他们执行多个测试?我是否必须编写自定义授权者(我该怎么做)?

此外,是否可以在其他地方使用提供给身份 validator 的凭据,例如将它们作为字符串传播到另一个方法? (如何)获取当前请求的 Identifier 和 Secret?

最佳答案

事实上,我认为你应该利用 ReSTLet 的角色支持。事实上,ReSTLet 提供了两个关于安全性的附加元素:

  • validator 根据请求中提供的凭据实际对用户进行身份验证
  • Enroler 用于加载经过身份验证的用户的角色。

以下是基本身份验证的示例:

@Override
public Restlet createInboundRoot() {
    Router router = (...)

    Verifier verify = new MyVerifier(...);
    Enroler enroler = new MyEnroler(...);

    ChallengeAuthenticator guard = new ChallengeAuthenticator(getContext(),
            ChallengeScheme.HTTP_BASIC, "connector");
    guard.setVerifier(verifier);
    guard.serEnrole(enroler);
    guard.setNext(router);

    return guard;
}

validator 的实现如下所示:

public class MyVerifier extends SecretVerifier {
    public int verify(String identifier, char[] secret)
                     throws IllegalArgumentException {
        ApplicationUser user = loadUser(identifier);
        //user contains both user hints and roles
        if (user!=null
              && compare(user.getPassword().toCharArray(), secret)) {
            Request request = Request.getCurrent();
            request.getClientInfo().setUser(user);
            return SecretVerifier.RESULT_VALID;
        } else {
            return SecretVerifier.RESULT_INVALID;
        }
    }
}

Enroler 的实现如下所示:

public class MyEnroler implements Enroler {
    public void enrole(ClientInfo clientInfo) {
        Request request = Request.getCurrent();
        User user = request.getClientInfo().getUser();
        if (user!=null) {
            List<UserRole> roles = user.getRoles();
            if (roles!=null) {
                for (UserRole userRole : roles) {
                    // example of role creation
                    Role role = new Role(userRole.getName(), "");
                    clientInfo.getRoles().add(role);
                }
            }
        }
    }
}

然后在资源中,您可以检查 ReSTLet 请求中可用的角色,以确定是否允许经过身份验证的用户执行该方法:

public MyServerResource extends ServerResource {
    private boolean hasRole(String expectedRole) {
        List<Role> roles = request.getClientInfo().getRoles();
        for (Role role : roles) {
            if (role.getName().equals(expectedRole)) {
                return true;
            }
        }
        return false;
    }

    private void checkRole(String role) {
        if (!hasRole(role)) {
            throw new ResourceException(
               Status.CLIENT_ERROR_FORBIDDEN);
        }
    }

    @Get
    public Representation getElement() {
        checkRole("read");
    }

    @Put
    public void updateElement(Representation repr) {
        checkRole("update");
    }

    @Delete
    public void deleteElement() {
        checkRole("delete");
    }
}

这种方法有点侵入性。您还可以拥有更通用的东西,但基于所使用的 HTTP 方法和角色。为此,我们需要实现一个自定义的 Authorizer 并像这样注册它:

    Router router = (...)

    Authorizer authorizer = new MyAuthorizer();
    authorizer.setNext(router);

    Verifier verify = new MyVerifier(...);
    Enroler enroler = new MyEnroler(...);

    ChallengeAuthenticator guard = new ChallengeAuthenticator(getContext(),
            ChallengeScheme.HTTP_BASIC, "connector");
    guard.setVerifier(verifier);
    guard.serEnrole(enroler);
    guard.setNext(authorizer);

    return guard;
}

这个Authorizer的实现可能是这样的:

public class MyAuthorizer extends Authorizer {
    private String[] getRoles = new String[] { "read"};
    private String[] putRoles = new String[] { "update"};
    private String[] deleteRoles = new String[] { "delete"};

    private boolean hasRoles(String[] expectedRoles) {
        List<Role> roles = request.getClientInfo().getRoles();
        for (String expectedRole : expectedRoles) {
            for (Role role : roles) {
                if (role.getName().equals(expectedRole)) {
                    return true;
                }
            }
        }
        return false;
    }

    private void checkRoles(String[] roles) {
        if (!hasRole(roles)) {
            throw new ResourceException(
               Status.CLIENT_ERROR_FORBIDDEN);
        }
    }

    public boolean authorize(Request request, Response response) {
        if (!request.getClientInfo().isAuthenticated()) {
            throw new ResourceException(
               Status.CLIENT_ERROR_FORBIDDEN);
        }

        if ("GET".equals(request.getMethod().getName())) {
            checkRoles(getRoles);
        } else if ("PUT".equals(request.getMethod().getName())) {
            checkRoles(putRoles);
        } else if ("DELETE".equals(request.getMethod().getName())) {
            checkRoles(deleteRoles);
        }

        return false;
    }
}

希望对你有帮助 蒂埃里

关于java - 按方法和用户进行 ReSTLet 授权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30028907/

相关文章:

c# - 有人可以向我解释这段 ASP.NET MVC 代码吗?

authentication - 如何在 Vaadin 应用程序中使用单点登录

java - 用编程语言执行类似电子表格的计算的好方法是什么?

java - 如何在 spring-data-jpa 中进行投影

java - 使用 toCharArray 检查 String 是否有任何非数字

Python登录网页获取session保护页面内容

java - 字符串不变性

asp.net - 托管 WCF 应用程序 IIS 身份验证

javascript - 如何使右箭头可点击,它应该模拟按下回车键

api - 使用 Python 的 Spotify API 授权代码流