RESTful服务中的资源级别授权

时间:2011-07-09 12:34:00

标签: rest authorization jax-rs restful-authentication

/users/{id}成为RESTful服务中的资源网址。

启用基本身份验证,只允许经过身份验证的用户访问该网址。

示例场景:

User_1& User_2是经过身份验证的用户,其userId为1& 2。 由于两者都经过身份验证,因此他们都可以访问

  • /users/1
  • /users/2

但期望User_1可以访问/users/1而不是/users/2或其他userId。

问题: 如何在RESTful服务中进行资源级别授权?

注意:我正在使用Jax-RS(使用Apache CXF实现)实现RESTful,如果您可以使用Jax-RS进行解释,这将非常有用。

-Barath

编辑:

正如Donal所说,我不是在寻找基于角色的授权而是资源级授权。

举个例子,假设/ users / {id} / photos / {photoId}是另一个资源网址。 User_1应该只能访问属于他的照片。如果photoId属于user_2,那么当请求request / users / 1 / photos / 2时,我们应该为user_1提供http_404错误代码。[由于User_1也是经过身份验证的用户,他可以调用/ users / 2 / photos / 2,因此我们必须根据身份验证参数识别用户ID,而不是通过资源网址

我能想到的唯一解决方案是,包括确定每个查询中授权的唯一ID,例如

而不是SELECT * FROM PHOTO_TBL WHERE PHOTO_ID=2;

使用SELECT * FROM PHOTO_TBL, USER_TBL WHERE PHOTO_ID=2 AND USER_ID=1 AND USER_ID=PHOTO_ID;

使用此资源提供属于特定用户的数据。 [应该有一种机制来阻止修改客户端中用于决定授权的唯一id(在本例中为userId),因为所有请求都是STATELESS请求]

警告:每个查询都应足够智能,以了解安全问题并包含额外的连接。这是一种糟糕的设计,可以将安全逻辑与每个业务功能联系起来。

我尚未研究Spring安全性以及如何在此用例中使用它。

2 个答案:

答案 0 :(得分:3)

我建议不要在url中使用用户ID(好像它被Basic Auth标头'限制'那么你也可以让它由Basic auth标头'指定'。这将降低引入直接对象引用漏洞 - https://www.owasp.org/index.php/Top_10_2010-A4-Insecure_Direct_Object_References

的风险

在这种情况下,您可以使用以下网址之一:

/users/CURRENT
/me

由于照片是子资源,因此您只需在用户中创建带有“序列号”的照片即可。在sql数据库中,这意味着在用户和照片列中都有一个“复合键”。

/users/CURRENT/photo/{user_photo_seq}
/me/photo/{user_photo_seq}

您的SQL看起来像:

SELECT * FROM PHOTO_TBL WHERE USER_ID=<BasicAuthUsername> AND PHOTO_ID=<path param value>;

对“基本身份验证标题”的一个很好的解释:

http://en.wikipedia.org/wiki/Basic_access_authentication

答案 1 :(得分:1)

JAX-RS specifies sub-resource而不是在方法中处理请求,处理被委托给其他对象 - 子资源。

使用子资源,它应该处理根资源,并且嵌套的资源也将得到保护。

在示例中,您可以看到UserResource及其所有子资源仅供授权用户使用。

@Path("/user/{userId}")
public class UserResource {

  private final String userId;

  public UserResource(@PathParam("userId") String userId, @Context SecurityContext securityContext) {
    this.userId = userId;

    boolean authorized = /* authorization code */;

    if (!authorized) { throw new WebApplicationException(Status.UNAUTHORIZED); }
  }

  @Path("photo")
  public PhotoResource getPhotoResource() {
    return new PhotoResource(userId);
  }

}

public class PhotoResource {

  private final String userId;

  public PhotoResource(String userId) {
    this.userId = userId;
  }

  @GET
  public Response listAll() { /* ... */ }

  @GET
  @Path("{photoId}")
  public Response present() { /* ... */ }

}