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