2017-01-17 8 views
2

Я хотел бы комбинировать функцию DeclarativeLinking от Джерси с его функцией RolesAllowed.Адресационные ссылки на объявление с использованием RolesAllowed

Я могу успешно вставлять ссылки в ответ, но эта инъекция не обращает внимания на аннотацию RolesAllowed этой конечной точки.

В качестве примера представьте двух пользователей. Назовите их администратором и пользователем. Оба могут получить доступ к ресурсам GET, но только администратор может получить доступ к DELETE.

Если метод ресурса защищен @RolesAllowed, то я ожидаю, что пользователь, который не имеет этой роли, не будет иметь эту конечную точку. Это, похоже, не так.

Я следовал примеру here.

Ниже приведена упрощенная версия проекта, над которым я работаю для иллюстративных целей.

Для администратора Я хотел бы ожидать следующий JSON,

{ 
    "id" : 1 
    "value" : "someValue", 
    "links" : [ 
     { 
      "href": "http://localhost/context/model/1", 
      "rel": "self", 
      "type": "GET" 
     }, 
     { 
      "href": "http://localhost/context/model/1", 
      "rel": "delete", 
      "type": "DELETE" 
     }, 
    }, 
} 

Это именно то, что я получаю. К сожалению, я также получаю этот ответ для пользователя, у которого нет правильных ролей, необходимых для доступа к этой конечной точке. Пользователь по-прежнему будет снабжен ссылкой на конечной точке удаления, но из-за RolesAllowed, что пользователь получит 403.

Модель

public class Model { 

private int id; 
private String value; 
//constructor/getters/setters 

представление модели

public class ModelRep { 
    @XmlPath(".") //Allows me to flatten json so that links and document are at the same level 
    private Model model; 

    @InjectLinks({ 
     @InjectLink(
      rel = "self", 
      type = "GET", 
      resource = ModelResource.class, 
      method = "getModel", 
      bindings = @Binding(name = "id", value = "${instance.id}"), 
      style = Style.ABSOLUTE 
     ), 
     @InjectLink(
      rel = "delete", 
      type = "DELETE", 
      resource = ModelResource.class, 
      method = "deleteModel", 
      bindings = @Binding(name = "id", value = "${instance.id}"), 
      style = Style.ABSOLUTE 
     ) 
    }) 
    @XmlJavaTypeAdapter(LinkAdapter.class) 
    private List<Link> links; 
    //constructor/getters/setters 

Модельный ресурс

@Path("/model") 
@Produces(MediaType.APPLICATION_JSON) 
public class ModelResource { 

    @GET 
    @Path("/{id}") 
    public Response getModel(@PathParam("id") int id) { 
     Model m = dao.get(id); 
     ModelRep mr = new modelRep(m); 
     GenericEntity<ModelRep> ent = new GenericEntity<ModelRep>(mr) {}; 
     return Response.status(Status.OK).entity(ent); 
    } 

    @DELETE 
    @Path("/{id}") 
    @RolesAllowed(Roles.ADMIN) 
    public Response deleteModel(@PathParam("id") int id) { 
     dao.delete(id); 
     return Response.status(Status.NO_CONTENT); 
    } 

Вопрос Есть ли способ, которым условная декларативная связь может быть достигнута на основе RolesAllowed?

Я знаю, что существует условие условия для аннотации InjectLink, но допустимыми для этого значениями являются экземпляр (ModelRep), сущность (объект ответа, я думаю?), Ресурс (ModelResource).

Я не знаю, как использовать любой из них для проверки разрешений.

Значительно признателен за любые советы

ответ

1

Так что я в конечном итоге найти решение, которое немного Hacky, но работает достаточно хорошо.

Каждый ресурс расширяет Clase ресурсной базой

@Path("/model") 
@Produces(MediaType.APPLICATION_JSON) 
public class ModelResource extends BaseResource { 

BaseResource определяет публичный метод, который возвращает ли или нет конкретный метод для текущего ресурса ограничена с аннотациями RolesAllowed.

public abstract class BaseResource { 

    @Context 
    private SecurityContext security; 

    public boolean isMethodRoleProtected(String sMethod) { 
     Method[] methods = this.getClass().getDeclaredMethods(); 
     for (Method m : methods) { 
      if (m.getName().equalsIgnoreCase(sMethod)) { 
       Annotation[] annotations = m.getAnnotations(); 
       for (Annotation a : annotations) { 
        if (a instanceof RolesAllowed) { 
         String[] roles = ((RolesAllowed) a).value; 
         return userHasRole(roles); 
        } 
       } 
      } 
     } 
     return false; 
    } 

    protected boolean userHasRole(String... roles) { 
     for (String role : roles) { 
      if (security.isUserInRole(role)) { 
       return true; 
      } 
     } 
     return false; 
    } 
} 

Наконец, аннотации InjectLink будут выглядеть следующим образом,

@InjectLink(
    rel = "self", 
    type = "GET", 
    resource = SomeResource.class, 
    method = "someMethod", 
    bindings = @Binding(name = "id", value = "${instance.id}"), 
    style = Style.ABSOLUTE, 
    condition = "${resource.isMethodRoleProtected(someMethod)}" 
), 

'Ресурс' является экземпляром текущего класса конечной точки, которая простирается BaseResource. Поэтому эта ссылка будет введена только в том случае, если текущий пользователь имеет роль, которая существует в аннотации RolesAllowed этого метода.

Это решение требует реализации SecurityContext.

Если у кого-то еще есть лучшее/более чистое решение или способ улучшить тот, который я нашел, я все равно хотел бы услышать и соответствующим образом настроить принятый ответ. Cheers

Смежные вопросы