# 设置扩展的权限

> 原文： [https://docs.oracle.com/javase/tutorial/ext/security/policy.html](https://docs.oracle.com/javase/tutorial/ext/security/policy.html)

如果[安全管理器](../../essential/environment/security.html)生效，则必须满足以下条件才能启用任何软件（包括扩展软件）执行安全敏感操作：

*   扩展中的安全敏感代码必须包装在`PrivilegedAction`对象中。
*   安全管理器实现的安全策略必须向扩展授予适当的权限。默认情况下，已安装的扩展会被授予所有安全权限，就好像它们是核心平台 API 的一部分一样。安全策略授予的权限仅适用于`PrivilegedAction`实例中包含的代码。

让我们通过一些例子更详细地看一下这些条件。

## 使用 PrivilegedAction 类

假设您要修改上一课的扩展示例中的`RectangleArea`类，将矩形区域写入文件而不是 stdout。但是，写入文件是一项对安全性敏感的操作，因此如果您的软件将在安全管理器下运行，则需要将您的代码标记为特权。您需要执行以下两个步骤：

1.  您需要在`java.security.PrivilegedAction`类型的对象的`run`方法中放置执行安全敏感操作的代码。
2.  在调用`java.security.AccessController`的`doPrivileged`方法时，必须使用`PrivilegedAction`对象作为参数。

如果我们将这些指南应用于`RectangleArea`类，我们的类定义将如下所示：

```
import java.io.*;
import java.security.*;

public final class RectangleArea {
    public static void
    writeArea(final java.awt.Rectangle r) {
        AccessController.
          doPrivileged(new PrivilegedAction() {
            public Object run() {
                try { 
                    int area = r.width * r.height;
                    String userHome = System.getProperty("user.home");
                    FileWriter fw = new FileWriter( userHome + File.separator
                        + "test" + File.separator + "area.txt");
                    fw.write("The rectangle's area is " + area);
                    fw.flush();
                    fw.close();
                } catch(IOException ioe) {
                    System.err.println(ioe);
                }
                return null;
            }
        });
    }
}

```

此类中的单个方法`writeArea`计算矩形区域，并将该区域写入用户主目录下`test`目录中名为`area.txt`的文件。

处理输出文件的安全敏感语句放在`PrivilegedAction`的新实例的`run`方法中。 （注意`run`要求返回`Object`实例。返回的对象可以是`null`。）然后新的`PrivilegedAction`实例作为参数传递给`AccessController.doPrivileged`。

有关使用`doPrivileged`的更多信息，请参阅 JDK™文档中的 [API for Privileged Blocks](https://docs.oracle.com/javase/8/docs/technotes/guides/security/doprivileged.html) 。

以这种方式在`PrivilegedAction`对象中包装安全敏感代码是使扩展能够执行安全敏感操作的第一个要求。第二个要求是：让安全管理器授予特权代码适当的权限。

## 使用安全策略指定权限

运行时生效的安全策略由 _ 策略文件 _ 指定。默认策略由 JRE 软件中的文件`lib/security/java.policy`设置。

策略文件使用 _grant_ 条目为软件分配安全权限。策略文件可以包含任意数量的授权条目。默认策略文件具有已安装扩展的此授权条目：

```
grant codeBase "file:${{java.ext.dirs}}/*" {
    permission java.security.AllPermission;
};

```

此条目指定由`file:${{java.ext.dirs}}/*`指定的目录中的文件被授予名为`java.security.AllPermission`的权限。 （注意，从 Java 6 开始，`java.ext.dirs`指的是类似`类路径`的目录路径，每个路径都可以保存已安装的扩展。）不难猜测`java.security.AllPermission`是否允许安装扩展可以授予的安全权限。

默认情况下，安装的扩展没有安全限制。扩展软件可以执行安全敏感操作，就像没有安装安全管理器一样，前提是安全敏感代码包含在作为`doPrivileged`调用中的参数传递的`PrivilegedAction`实例中。

要限制授予扩展的权限，您需要修改策略文件。要拒绝所有扩展的所有权限，您只需删除上述授权条目即可。

并非所有权限都与默认授予的`java.security.AllPermission`一样全面。删除默认授权条目后，您可以输入特定权限的新授权条目，包括：

*   `java.awt。 **AWTPermission**`
*   `java.io. **FilePermission**`
*   `java.net。 **NetPermission**`
*   `java.util。 **PropertyPermission**`
*   `java.lang.reflect。 **ReflectPermission**`
*   `java.lang。 **RuntimePermission**`
*   `java.security。 **SecurityPermission**`
*   `java.io. **SerializablePermission**`
*   `java.net。 **SocketPermission**`

JDK 文档中的[权限提供了有关这些权限的详细信息。让我们看一下使用 RectangleArea 作为扩展所需的那些。](https://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html)

`RectangleArea.writeArea`方法需要两个权限：一个用于确定用户主目录的路径，另一个用于写入文件。假设`RectangleArea`类捆绑在文件`area.jar`中，您可以通过将此条目添加到策略文件来授予写入权限：

```
grant codeBase "file:${java.home}/lib/ext/area.jar" {
    permission java.io.PropertyPermission "user.home",
        "read";
    permission java.io.FilePermission
        "${user.home}${/}test${/}*", "write";
};

```

此条目的`codeBase "file:${java.home}/lib/ext/area.jar"`部分保证此条目指定的任何权限仅适用于`area.jar`。 `java.io.PropertyPermission`允许访问属性。第一个参数`"user.home"`命名属性，第二个参数`"read"`表示可以读取属性。 （另一种选择是`"write"`。）

`java.io.FilePermission`允许访问文件。第一个参数`"${user.home}${/}test${/}*"`表示`area.jar`被授予访问用户主目录中`test`目录中所有文件的权限。 （请注意，`${/}`是与平台无关的文件分隔符。）第二个参数表示授予的文件访问权限仅用于写入。 （第二个参数的其他选择是`"read"`，`"delete"`和`"execute"`。）

## 签署扩展程序

您可以使用策略文件对授予扩展的权限设置其他限制，方法是要求它们由可信实体签名。 （有关签名和验证 JAR 文件的评论，请参阅本教程中的[签名 JAR 文件](../../deployment/jar/signing.html)课程。）

要允许签名验证扩展或其他软件以及授予权限，策略文件必须包含 _ 密钥库条目 _。 keystore 条目指定在验证中使用哪个密钥库。密钥库条目具有表单

```
keystore "keystore_url";

```

URL _keystore_url_ 是绝对的或相对的。如果它是相对的，则 URL 相对于策略文件的位置。例如，要使用 `keytool` 使用的默认密钥库，请将此条目添加到 `java.policy`

```
keystore "file://${user.home}/.keystore";

```

要指示必须签署扩展才能获得安全权限，请使用`signedBy`字段。例如，以下条目表示仅当扩展名`area.jar`由别名 Robert 和 Rita 在密钥库中标识的用户签名时才会授予列出的权限：

```
grant signedBy "Robert,Rita",
    codeBase "file:${java.home}/lib/ext/area.jar" {
        permission java.io.PropertyPermission
            "user.home", "read";
        permission java.io.FilePermission
            "${user.home}${/}test${/}*", "write";
};

```

如果省略`codeBase`字段，如下面的“grant”，则授予 _ 任何 _ 软件的权限，包括由“Robert”或“Rita”签名的已安装或下载扩展名：

```
grant signedBy "Robert,Rita" {
    permission java.io.FilePermission "*", "write";  
};

```

有关策略文件格式的更多详细信息，请参阅 JDK 文档中[安全体系结构规范](https://docs.oracle.com/javase/8/docs/technotes/guides/security/spec/security-spec.doc3.html#20131)的第 3.3.1 节。