按方法和用户的 Restlet 授权
Restlet Authorization by Method AND User
我是 Restlet 和 REST 的新手,想为 运行 服务器/数据库实现 RESTful API。到目前为止,路由和寻址似乎工作正常,但我需要一些有关如何处理身份验证和授权的提示。
情况:有些资源只有一些用户只能以某些方式与之交互。例如,User1 可能能够获取资源,但不能 PUT 任何东西,而 User2 可以同时执行这两项操作,而 User3 甚至可能不会读取它,而 User4 是唯一允许使用 DELETE 的人。
当然有 MethodAuthorizer 听起来很有希望,但它似乎只区分匿名用户和(所有)经过身份验证的用户。另一方面,RoleAuthorizer 不会区分 GET、PUT 或其他请求方法,只会区分资源。
我如何才能只授权某些用户只执行某些任务?有没有办法组合授权者,或者让他们执行多个测试?我是否必须编写自定义授权器(我该怎么做)?
此外,是否可以在其他地方使用提供给 Authenticator 的凭据,例如通过将它们作为字符串传播到另一种方法? (如何)获取当前请求的Identifier和Secret?
事实上,我认为您应该利用 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;
}
}
希望对你有帮助,
蒂埃里
我是 Restlet 和 REST 的新手,想为 运行 服务器/数据库实现 RESTful API。到目前为止,路由和寻址似乎工作正常,但我需要一些有关如何处理身份验证和授权的提示。
情况:有些资源只有一些用户只能以某些方式与之交互。例如,User1 可能能够获取资源,但不能 PUT 任何东西,而 User2 可以同时执行这两项操作,而 User3 甚至可能不会读取它,而 User4 是唯一允许使用 DELETE 的人。
当然有 MethodAuthorizer 听起来很有希望,但它似乎只区分匿名用户和(所有)经过身份验证的用户。另一方面,RoleAuthorizer 不会区分 GET、PUT 或其他请求方法,只会区分资源。
我如何才能只授权某些用户只执行某些任务?有没有办法组合授权者,或者让他们执行多个测试?我是否必须编写自定义授权器(我该怎么做)?
此外,是否可以在其他地方使用提供给 Authenticator 的凭据,例如通过将它们作为字符串传播到另一种方法? (如何)获取当前请求的Identifier和Secret?
事实上,我认为您应该利用 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;
}
}
希望对你有帮助, 蒂埃里