2

我一直在尝试保护一个应用程序,该应用程序使用注释而不是部署描述符部署到 glassfish 3。但是,我无法让它正常工作。如果我尝试访问该服务,最终会出现服务器错误 500,其中显示以下消息:

type Exception report

message

descriptionThe server encountered an internal error () that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: javax.ejb.AccessLocalException: Client not authorized for this invocation
root cause

javax.ejb.AccessLocalException: Client not authorized for this invocation

EJB 看起来像这样:

@Path("/myresource")
@Stateless
@RolesAllowed("user-role")
public class MyResource {

    @GET
    @Path("/{uuid}")
    public Response getData(@PathParam("uuid") final String uuid) {
            ....
    }
}

太阳-web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD GlassFish Application Server 3.0 Servlet 3.0//EN" 
"http://www.sun.com/software/appserver/dtds/sun-web-app_3_0-0.dtd">
<sun-web-app>
    <security-role-mapping>
        <role-name>user-role</role-name>
        <group-name>user-group</group-name>
    </security-role-mapping>
</sun-web-app>

这是 web.xml:

<web-app id="myservice" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <display-name>org.test.myservice</display-name>

    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>org.test.myservice.rest</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>file</realm-name>
    </login-config>

    <security-role>
        <role-name>user-role</role-name>
    </security-role>
</web-app>

glassfish 中的文件领域是使用 sun-web.xml 中指定的用户和角色设置的,并且在通过部署描述符设置应用程序安全性时运行良好。

如果我正确理解了本文档,我不必链接安全角色引用(如果它们的名称相同)。http://docs.oracle.com/javaee/5/tutorial/doc/bnbyl.html#bnbyt 有什么我想念的想法吗?

编辑 与无法通过注解指定所需信息的问题相关,还有一个问题,引起了我对这个问题的思考。也许这会使最初的问题更清楚一点:以上面的例子为例,资源 /myresource/* 仅适用于角色为“user-role”的用户。但是,如果在路径 /myresource/*/thumbnail (转换为 /myresource/[uuid]/thumbnail)处有第二个资源应该无需身份验证即可使用,则通过使用 url-mapping 指定安全约束是不可能的,因为似乎不可能在常量之间使用通配符。但是,这可以通过指定角色来实现,这些角色允许通过注释访问方法。如上所述,我无法这样做。这样的映射怎么可能完成?

4

2 回答 2

2

您需要使用 web.xml 描述符中的security-constraint元素来阻止特定资源和路径,并指定授权约束。

这并不意味着您不能使用 Programmatic Security 添加更细粒度的控件,如Oracle 的 Java EE 6 教程中所述:

程序化安全嵌入在应用程序中,用于做出安全决策。当仅声明式安全不足以表达应用程序的安全模型时,程序安全很有用。


根据您编辑的问题。

我会使用该security-constraint元素来阻止对所有非注册用户的访问。这将强制每个人进行身份验证,以便您的应用程序知道他们拥有的角色。然后,您可以使用编程安全性精细控制对各种资源的访问。

有了基本身份验证,我想没有其他方法了。如果您想避免对基本用户进行身份验证,则需要使用表单身份验证并在后台以编程方式处理身份验证,即使他们不知道,也可以使用HttpServletRequest#login()对其进行身份验证。

在这两种方式中,您都应该能够按照您描述的方式设置权限。如果您想更顺利地处理未经授权的异常,您最好删除@RolesAllowed注释并改用以下内容:

@GET
@Path("/{uuid}")
public Response getData(@PathParam("uuid") final String uuid, @Context SecurityContext sc) {
    if (sc.isUserInRole("MyRole")) {
        return result;
    } else {
        return notAllowedResult;
    }
}
于 2012-12-03T13:29:43.547 回答
2

Roles-Allowed 是一个 EJB 构造,与对资源的访问不一致,由安全约束处理。

不幸的是,这两个安全概念并没有像应有的那样紧密结合,如果您没有获得授权(Web 概念),您不会得到 401,而是会收到您正在接收的安全异常(和 EJB 概念)。事实上,如果您使用 RolesAllowed 注释 EJB Web 服务并尝试使用无效角色访问 Web 服务,我不知道您会收到什么错误。在这种情况下,我假设您会遇到 SOAP 错误。

EJB 安全性是一个将未经授权的人员拒之门外的系统,但它是最后的努力。它假定任何将人们路由到方法调用的决定都已经预先完成。例如,没有高级方法来测试一个方法是否被允许,而你只能调用它并捕获异常。

因此,严酷的事实超出了粗略的看门人,您想要利用程序安全性。

于 2012-12-03T14:42:13.100 回答