如何保护 REST 资源的安全,以便只有角色的单个用户才能访问它?

发布于 2025-01-08 01:37:32 字数 2120 浏览 2 评论 0原文

我已经使用 Jersey 成功创建了一个 REST Web 服务,并通过 java 安全注释保护它。 看起来像这样

GET    /users/     // gives me all users
GET    /users/{id} // gives the user identified by {id}
POST   /users/     // creates user
PUT    /users/{id} // updates user identified by {id}
DELETE /users/{id} // delete user

我还设置了一个具有两个角色的领域:用户和管理员

我保护了所有方法,以便只有管理员可以访问它们。

现在我想免费提供 PUT /users/{id}GET /users/{id} 方法,以便用户可以访问他们自己的并且只有他们自己的资源。

示例:

// user anna is logged in and uses the following methods
    GET    /users/anna // returns 200 OK
    GET    /users/pete // returns 401 UNAUTHORIZED

由于我找不到通过注释进行配置的方法,因此我正在考虑将 HTTP 请求传递给相应的方法来检查是否允许用户访问该资源。

对于 GET /users/{id} 方法来说,它看起来像这样:

@GET
@Path("/users/{id}")
@RolesAllowed({"admin","user"})
@Produces(MediaType.APPLICATION_JSON)
public Response getUser(
    @PathParam("id") String id,
    @Context HttpServletRequest req
) {
    HttpSession session = request.getSession(false);

    if (session != null && session.getValue("userID").equals(id))
        return getObject(User.class, id);

    return Response.status(Status.UNAUTHORIZED).build();
}

我不喜欢这种方法,因为我认为我必须手动将 userID 添加到会话中。

  • 你知道一个更优雅的方法来解决这个问题吗?

  • 如果不是,如何在使用表单身份验证时将用户 ID 添加到会话?

编辑

谢谢威尔和帕维尔:)这是我的最终解决方案:

@Context
private SecurityContext security;

// ...
@GET
@Path("/users/{id}")
@RolesAllowed({"admin","user"})
@Produces(MediaType.APPLICATION_JSON)
public Response getUser(@PathParam("id") String id){
    if (security.isUserInRole("user"))
        if (security.getUserPrincipal().getName().equals(id))
            return getObject(User.class, id);
        else
            return Response.status(Status.UNAUTHORIZED).build();
    else
        return getObject(User.class, id);
}

I have succesfully created a REST web service with Jersey and secured it via java security annotations.
It looks something like this

GET    /users/     // gives me all users
GET    /users/{id} // gives the user identified by {id}
POST   /users/     // creates user
PUT    /users/{id} // updates user identified by {id}
DELETE /users/{id} // delete user

I also have setup a realm with two roles: user and admin

I secured all methods so that only admins can access them.

Now i want to give free the PUT /users/{id} and GET /users/{id} methods, so that users can access their own and only their own resources.

Example:

// user anna is logged in and uses the following methods
    GET    /users/anna // returns 200 OK
    GET    /users/pete // returns 401 UNAUTHORIZED

Since i could not find a way to configure this through annotations, I am thinking of passing the HTTP request to the corresponding method to check if the user is allowed to access the resource.

It would look something like this for the GET /users/{id} method:

@GET
@Path("/users/{id}")
@RolesAllowed({"admin","user"})
@Produces(MediaType.APPLICATION_JSON)
public Response getUser(
    @PathParam("id") String id,
    @Context HttpServletRequest req
) {
    HttpSession session = request.getSession(false);

    if (session != null && session.getValue("userID").equals(id))
        return getObject(User.class, id);

    return Response.status(Status.UNAUTHORIZED).build();
}

I don't like this aproach because i think i would have to add the userID manualy to the session.

  • Do you know a more elegant way to solve this?

  • If not how do you add the userid to the session while using form authentication?

EDIT

Thank you Will and Pavel :) Here is my final solution:

@Context
private SecurityContext security;

// ...
@GET
@Path("/users/{id}")
@RolesAllowed({"admin","user"})
@Produces(MediaType.APPLICATION_JSON)
public Response getUser(@PathParam("id") String id){
    if (security.isUserInRole("user"))
        if (security.getUserPrincipal().getName().equals(id))
            return getObject(User.class, id);
        else
            return Response.status(Status.UNAUTHORIZED).build();
    else
        return getObject(User.class, id);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

随梦而飞# 2025-01-15 01:37:32

HttpServletRequest中,您可以调用getRemoteUser()getUserPrincipal()来获取登录用户的身份。然后,您将继续像您正在做的那样,专门允许或拒绝他们访问特定资源。

Blessed Geek 更具体地指的是有关无状态事务和 HTTP 身份验证的使用的 REST 方面。虽然这是更大范围的 REST 架构中的一个重要点,但它与您的具体问题不太相关,因为您没有指定针对 Java EE 应用程序使用的身份验证机制的类型,特别是因为身份验证是一个容器问题在 Java EE 中,不是应用程序问题。

如果您使用基本身份验证,那么您将使用 HTTP 标头来管理身份验证和授权。如果您使用基于表单的身份验证,那么容器将通过 servlet 会话为您管理此身份验证,从而使服务有状态(因为会话是有状态的工件)。

但这与你的具体问题无关。

In the HttpServletRequest, you can call getRemoteUser() or getUserPrincipal() to get the identity of the logged in user. You would then continue like you are doing in specifically allowing or denying them access to the particular resource.

Blessed Geek is referring more specifically to the aspect of REST regarding stateless transactions and the use of HTTP authentication. While this is an important point in the larger scope of a REST architecture, it's less relevant to your specific question since you don't specify the type of authentication mechanism you're using against your Java EE app, especially since authentication is a container issue in Java EE, not an application issue.

If you're using basic authentication, then you are using HTTP headers to manage authentication and authorization. If you're using form based authentication, then the container is managing this for you via the servlet session, making the service stateful (since sessions are a stateful artifact).

But this has no bearing on your specific question.

新一帅帅 2025-01-15 01:37:32

部署 REST 最重要的方面之一是了解 http 标头和 cookie 的作用。

为了使 REST 实用,您需要部署一个身份验证框架。

请阅读

GWT 和 Google Docs API

GWT 平台登录 + 会话管理

了解 Google 联合登录, OAuth 和 OpenID。

如果我的一些解释是在 OAuth 2.0 之前发布的,那么它们可能已经过时。

One of the most important aspects of deploying REST is understanding the role of http headers and cookies.

For REST to be practical, you need to deploy an authentication framework.

Read

GWT and Google Docs API.

GWT-Platform login + session management

Read up on Google Federated Login, OAuth and OpenID.

Some of my explanations may be outdated, if they were posted before OAuth 2.0.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文