【问题标题】:Restlet Authorization by Method AND User方法和用户的 Restlet 授权
【发布时间】:2015-05-04 11:23:01
【问题描述】:

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

情况:有些资源只有某些用户才能以某些方式与之交互。例如,User1 可能能够 GET 资源,但不能 PUT 任何东西,而 User2 可以两者都做,User3 甚至可能不会读取它,而 User4 是唯一允许使用 DELETE 的人。

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

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

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

【问题讨论】:

    标签: java authentication authorization restlet


    【解决方案1】:

    事实上,我认为你应该利用 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;
        }
    }
    

    希望对你有帮助 蒂埃里

    【讨论】:

    • 非常感谢,蒂埃里!这设法让我获得了一个 Enroler/Authorizer 组合,只允许具有某些角色的用户执行他们各自的请求。有些事情并没有完全按照书面说明进行。例如"GET".equals(request.getMethod()) 之类的方法返回 false,除非我 toString() 他们,或者 'request.getAttributes().put("currentUser");' 必须更改为 'User user = (User) clientInfo。获取用户();'。不过,代码提供了很大的帮助,而且从那里开始并不难。也许我只是有一个不同的 Restlet 版本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 2022-11-10
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多