@RunAs javax 安全注释有什么用?

What is the use of @RunAs javax security annotation?

我试图从 java docs 中理解 @RunAs 注释的用法,但我不理解它的用法。谁能解释一下?

我的理解是,在某些情况下,如果具有不同角色的经过身份验证的用户想要访问仅允许具有特定角色的用户访问的 ejb 方法,则调用者 ejb 可以将自己注释为成为 运行 预期的角色并可以访问 ejb 方法。

所以我写了下面的代码,但是我的理解是错误的。

JAX-RS Class:

package com.jee.beginner.rest;

import java.security.Principal;

import javax.inject.Inject;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.groups.ConvertGroup;
import javax.validation.groups.Default;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;

import com.jee.beginner.custom.validation.Create;
import com.jee.beginner.custom.validation.Update;
import com.jee.beginner.domain.Student;
import com.jee.beginner.service.StudentService;
import com.jee.beginner.service.proxy.StudentServiceProxy;

@Path("student")
public class StudentResource {

    @Inject
    private Principal principal;

    @Inject
    private StudentService studentService;

    @Inject
    private StudentServiceProxy studentServiceProxy;

    @GET
    @Path("details/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Student getDetails(@PathParam("id") @Min(value = 2, message = "ID cannot be less than 2") int id,
            @QueryParam("id") int qid, @Context UriInfo uriInfo) {

        return studentServiceProxy.getDetails(id);
    }

    @POST
    @Path("new")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Student addStudent(@Valid @ConvertGroup(from = Default.class, to = Create.class) final Student student) {

        return studentService.addStudent(student);
    }

    @POST
    @Path("update")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Student updateStudent(@Valid @ConvertGroup(from = Default.class, to = Update.class) final Student student) {

        return student;
    }
}

代理 class。这个class被注释为@RunAs("admin")

package com.jee.beginner.service.proxy;

import javax.annotation.security.RunAs;
import javax.ejb.Stateless;
import javax.inject.Inject;

import com.jee.beginner.domain.Student;
import com.jee.beginner.service.StudentService;

@RunAs("admin")
@Stateless
public class StudentServiceProxy {

    @Inject
    private StudentService studentService;

    public Student getDetails(int id) {
        return studentService.getDetails(id);
    }
}

服务class:

package com.jee.beginner.service;

import javax.annotation.Resource;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJBContext;
import javax.ejb.Stateless;

import com.jee.beginner.domain.Student;

@Stateless
public class StudentService {

    @Resource
    private EJBContext context;

    @RolesAllowed({ "admin", "guest" })
    public Student addStudent(final Student student) {
        System.out.println(context.isCallerInRole("admin"));
        return student;
    }

    @RolesAllowed({ "admin" })
    public Student getDetails(int id) {
        Student student = new Student();
        student.setId(id);
        student.setName("noname");
        return student;
    }
}

我创建了一个领域并添加了两个用户

UserA - 管理员, 用户 B - 访客

没有 RunAs 注释,UserA 能够按预期访问该方法,而 UserB 无法按预期访问该方法。

我添加 RunAs 注释后,两个用户都无法访问 getDetails 方法。

我认为 UserB 现在可以访问该方法,因为代理被注释为 RunAs 管理员,我认为 StudentService 会将用户视为管理员角色。但实际上发生的是 UserA 也无法访问该方法。

谁能解释一下 RunAs 注释的意义?

通常,EJB 方法将作为经过身份验证的用户的某些操作的结果被同步调用。应用程序服务器随调用一起传播用户的安全上下文,EJB 容器可以使用此上下文来验证调用者是否与该方法的允许角色相关联。

但是,在某些情况下,可以在没有经过身份验证的用户参与的情况下调用 EJB 方法。这些情况包括:

  • 执行 EJB 定时器
  • 执行消息驱动 bean (MDB)

例如,您可能已经定义了一个应该执行的定期服务:

@Stateless
public class StudentService {

     @Timeout
     @Schedule(...)
     @RunAs("admin")
     public void periodicCheck(Timer timer) {
         ...
     }

}

这里使用javax.annotation.security.RunAs表示该方法要以"admin"角色执行

@RunAs 批注可用于@Steve C 指出的用例,也可用于您描述的确切用例。

您的代码和您的假设是正确的。它不起作用,因为某些容器(例如 Wildfly)默认实现 EJB 方法权限的方式。当根本不使用安全注解时,所有方法都被假定为 unchecked,就好像它们使用 @PermitAll 进行注解一样。但是,当在您的部署中使用任何安全注释并且方法没有明确的权限(在 class 级别或方法级别)时,Wildfly 将其视为拥有 @DenyAll.

所以,你的StudentService是正确的,但是在你的StudentServiceProxy中,getDetails方法没有任何方法权限。您应该使用 @PermitAll (任何用户、事件未经身份验证的用户可以执行它)、@RolesAllowed({ "**" }) (任何经过身份验证的用户可以执行它)对其进行注释(在方法级别或 class 级别) , 或 @RolesAllowed({ "admin", "guest" }) (具有管理员或来宾角色的用户执行它)。

如果使用 wildfly/jboss,您还可以更改 ejb3 子系统的默认行为。检查:https://docs.jboss.org/author/display/WFLY/Securing+EJBs