热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

方法和用户的Restlet授权-RestletAuthorizationbyMethodANDUser

ImnewtoRestletandRESTingeneralandwanttoimplementaRESTfulAPIforarunningserverda

I'm new to Restlet and REST in general and want to implement a RESTful API for a running server / database. Routing and addressing seems to work fine so far but I'll need a few hints at how to handle authentication and authorization.

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

The situation: There are some resources with which only some users can interact in only some ways. For example, User1 might be able to GET a resource, but not PUT anything, while User2 can do both, User3 might not even read it, and User4 ist the only one allowed to use DELETE.

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

There is, of course, the MethodAuthorizer that sounded promising but it seems that it only discriminates between anonymous and (all) authenticated users. A RoleAuthorizer, on the other claw, won't distinguish between GET, PUT or other request methods, only between resources.

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

How would I go about authorizing only certain users to do only certain tasks? Is there a way to combine Authorizers, or have them execute multiple tests? Do I have to write a custom Authorizer (how would I do that)?

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

Also, would it be possible to use the credentials given to an Authenticator somewhere else, for example by propagating them as Strings to another method? (How) can you get the Identifier and Secret of a current request?

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

1 个解决方案

#1


In fact, I think that you should leverage the role support of Restlet. In fact, Restlet provides two additional elements regarding security:

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

  • Verifier that actually authenticates the user based on provided credentials within the request
  • 验证程序实际上根据请求中提供的凭据对用户进行身份验证

  • Enroler that loads the roles of the authenticated user.
  • Enroler加载经过身份验证的用户的角色。

Here is a sample for a basic authentication:

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

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

The implementation of the Verifier looks like this:

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

The implementation of the Enroler looks like this:

Enroler的实现如下:

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

Then within the resources, you can check the roles available within the Restlet request to determine if the authenticated user is allowed to execute the method:

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

public MyServerResource extends ServerResource {
    private boolean hasRole(String expectedRole) {
        List 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");
    }
}

This approach is a bit intrusive. You could also have something more general but based on the HTTP method used and roles. For this, we need to implement a custom Authorizer and register it like this:

这种方法有点干扰。您还可以使用更一般的东西,但基于使用的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;
}

The implementation of this Authorizer could be something like that:

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

Hope it helps you, Thierry

希望它对你有帮助,蒂埃里


推荐阅读
author-avatar
易中天我最爱
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有