方法和用户的Restlet授权

时间:2015-05-04 11:23:02

标签: java authentication authorization restlet

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

情况:有些资源只有部分用户可以通过某种方式进行交互。例如,User1可能能够获取资源,但不能PUT任何东西,而User2可以同时执行这两项操作,User3甚至可能不会读取它,而User4是唯一允许使用DELETE的用户。

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

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

此外,是否可以使用在其他地方为Authenticator提供的凭据,例如将它们作为字符串传播到另一个方法? (如何)你能获得当前请求的标识符和秘密吗?

1 个答案:

答案 0 :(得分:2)

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

  • Verifier实际根据请求中提供的凭据对用户进行身份验证
  • 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;
}

Verifier的实现如下:

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;
    }
}

希望它可以帮到你, 亨利