将Tivoli Access Manager 与 ObjectGrid 集成以对分布式客户机进行身份验证和授权

在本文中,我们将首先了解 ObjectGrid 身份验证和授权的信息,然后了解如何将 IBM® Tivoli® Access Manager 与 ObjectGrid 集成,以提供安全的企业分布式缓存解决方案。文中提供了一个示例,演示了如何完成此集成任务。

引言

IBM® WebSphere® Extended Deployment V6.1 的 ObjectGrid 组件是用于 Java™ 对象的启用了网格的内存内数据存储区,专门针对可伸缩性、弹性和高性能进行了精心设计。ObjectGrid 可以像使用内存内数据库一样使用,也可以使用其将数据分布在网络上。

ObjectGrid 为 Java 身份验证和授权服务(Java Authentication and Authorization Service,JAAS)提供即时可用的安全性支持。不过,由于 JAAS 基于 CodeSource 而且使用纯文本格式处理文件实现,因此可能不足以有效地保护企业应用程序。由于这个原因,ObjectGrid 还具有与其他企业安全性软件集成的功能。

用于电子商务的 IBM Tivoli® Access Manager 是使用广泛的企业级安全性解决方案,能为企业环境提供完整的身份验证和授权解决方案,还全面支持 JAAS。ObjectGrid 可以与 Tivoli Access Manager 集成,以实现安全的分布式缓存解决方案。

本文将介绍如何使用 Tivoli Access Manager Authorization Java API 对分布式 ObjectGrid 客户机进行身份验证和授权,其中包括用于说明如何完成此集成的代码示例。本文要求您了解 Java 编程功能、ObjectGrid 和 Tivoli Access Manager 的基本知识并熟悉授权和身份验证的概念。有关更多信息,请参见参考资料。

ObjectGrid 安全性概述

分布式 ObjectGrid 可在 ObjectGrid 服务器中承载数据,而 ObjectGrid 客户机可通过连接到服务器来读取或更新数据。ObjectGrid 采用开放的安全性体系结构来对客户机进行身份验证和授权。开放安全性体系结构允许 ObjectGrid 与外部安全性产品实现集成(请参见参考资料)。

与在任何安全的分布式环境中一样,身份验证和授权是安全的分布式 ObjectGrid 系统中两个最为重要的安全功能。ObjectGrid 客户机必须提供凭据才能通过 ObjectGrid 服务器的身份验证,而且此客户机必须得到授权才能调用 ObjectGrid 操作。ObjectGrid 自己并不提供任何现成的安全性实现,但提供了安全性插件,以便实现您所选择的安全性机制。

图 1 显示了 ObjectGrid 服务器如何对客户机进行身份验证和授权。步骤 1 到 6 显示了身份验证流程,而步骤 7 到 9 显示了授权流程。三个绿色的环表示 ObjectGrid 插件,而两个黄色的柱面表示外部安全服务。


图 1. ObjectGrid 身份验证和授权体系结构
图 1. ObjectGrid 身份验证和授权体系结构

  • 身份验证流
    1. 身份验证流从 ObjectGrid 客户机获取代表自己的凭据开始。此工作由插件 com.ibm.websphere.objectgrid.security.plugins.CredentialGenerator 进行。
    2. 简单说来,CredentialGenerator 对象知道如何生成有效的客户机凭据,例如用户 ID/密码对、Kerberos 票据等等。
    3. ObjectGrid 客户机使用 CredentialGenerator 对象接收到 Credential 对象后,会将此客户机 Credential 对象随 ObjectGrid 请求一起发送到 ObjectGrid 服务器。
    4. ObjectGrid 服务器在处理 ObjectGrid 请求前将对 Credential 对象进行身份验证。ObjectGrid 服务器使用 Authenticator 插件对 Credential 对象进行身份验证。
    5. Authenticator 插件表示指向用户注册中心的接口,例如 LDAP 服务器或操作系统用户注册表。Authenticator 查询用户注册中心,并作出身份验证决策。
    6. 如果身份验证成功,将会返回表示此客户机的 Subject 对象。
  • 授权流

    ObjectGrid 采用基于权限的授权机制。ObjectGrid 具有代表不同权限类的不同权限类别。例如,com.ibm.websphere.objectgrid.security.MapPermission 代表在 ObjectMap 中对数据项进行读取、写入、插入、作废和删除操作。由于 ObjectGrid 提供 JAAS 授权的现成支持,因此可以利用 JAAS 通过提供授权策略处理 ObjectGrid 授权。此外,ObjectGrid 还支持自定义授权。自定义授权通过插件 com.ibm.websphere.objectgrid.security.plugins.ObjectGridAuthorization 插入。

    1. 服务器运行时将 Subject 对象和所需的权限发送到 ObjectGrid 授权插件中。
    2. ObjectGrid 授权插件查询 Authorization 服务并作出授权决策。如果为此 Subject 对象授予了权限,将会返回“true”值,否则会返回“false”。
    3. 此授权决策(true 或 false)将返回到服务器运行时。

有关其他权限类型和安全插件的更多信息,请参见 ObjectGrid Security JavaDoc

集成 Tivoli Access Manager

在组成 Tivoli Access Manager(以下称为 Access Manager)的众多组件中,需要以下组件来运行本文中的示例:

  • Access Manager Directory Server 是受支持操作系统的轻量级目录访问协议(Lightweight Directory Access Protocol,LDAP)的 IBM 实现。Directory Server 提供了使用 IBM DB2® 数据库存储目录信息的服务器,用于将 LDAP 操作路由到其他服务器的代理服务器、客户机及用于管理服务器的图形用户界面。

  • Access Manager Policy Server 维护管理域的主授权数据库以及与您可能决定创建的其他安全域关联的策略数据库。

  • Access Manager Authorization Server 在存在以远程缓存模式使用 Tivoli Access Manager 授权 API 的第三方应用程序的情况下,提供对此类应用程序的授权服务的访问。它可在第三方应用程序(如 ObjectGrid)和 Access Manager Policy Server 间起到桥梁纽带的作用。

  • Access Manager Runtime for Java 提供了可靠的环境,可用于在 Tivoli Access Manager 安全域中开发和部署 Java 应用程序。可以将其用于向新的或现有的 Java 应用程序添加 Tivoli Access Manager 授权和安全服务。

正如图 1 中所示,需要创建三个插件,以便将 Access Manager 用于对 ObjectGrid 进行身份验证和授权:

  • CredentialGenerator 和 Credential

    Credential 对象代表客户机凭据,如用户 ID/密码对、Kerberos 票据等。CredentialGenrator 对象代表创建凭据的凭据工厂。例如,如果凭据是 Kerberos 票据,CredentialGenerator 将创建 Kerberos 票据。Kerberos 票据过期后,CredentialGenerator 应该能够续订票据。

    在此集成示例中,凭据是存储在目录服务器中的用户 ID/密码对。因此,您可以使用这两个接口的 ObjectGrid 内置实现来处理用户 ID/密码对:

    • com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredentialGenerator
    • com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredential

    UserPasswordCredential 类包含两个字符串属性:一个用于用户 ID,另一个用于密码。UserPasswordCredentialGenerator 类只创建预先设置的 UserPasswordCredential 对象(请参见参考资料)。

  • 身份验证者

    Access Manager 提供了登录模块 com.tivoli.mts.PDLoginModule,用于支持 JAAS 身份验证。此登录模型类需要调用应用程序提供以下信息:

    • 主体名称,采用短名称或 X.500 名称 (DN) 指定。
    • 密码。

    com.tivoli.mts.PDLoginModule 模块对主体进行身份验证,并返回 Access Manager 凭据。它预期调用应用程序提供以下信息:

    • 用户 ID,通过 javax.security.auth.callback.NameCallback
    • 密码,通过 javax.security.auth.callback.PasswordCallback

    成功检索了 Access Manager 凭据后,登录模块将创建 Subject 对象和 PDPrincipal 对象。为此示例创建了简单的回调处理程序类 com.ibm.websphere.samples.objectgrid.security.tam.UserPasswordCallbackImpl,用于将用户密码对传递给 PDLoginModule,以进行身份验证。示例代码打包在随本文提供的下载文件中。

    清单 1 显示了 Authenticator 实现类中的 com.ibm.websphere.samples.objectgrid.security.tam.TAMAuthenticator 身份验证方法。您将会看到,其中利用了 JAAS 身份验证服务来使用登录名登录到 Access Manager。



    清单 1. TAMAuthenticator.authenticate(Credential) 方法
                            
    subject = (Subject) AccessController.doPrivileged(new PrivilegedExceptionAction() {
        public Object run() throws InvalidCredentialException, 
        ExpiredCredentialException 
        {
            UserPasswordCredential cred = (UserPasswordCredential) credential;
            LoginContext lc = null;
            try {
                lc = new LoginContext(loginName, new UserPasswordCallbackHandlerImpl(cred
    			.getUserName(), cred.getPassword().toCharArray()));
    
                lc.login();
    
                Subject s = lc.getSubject();
                System.out.println("The authenticated subject is " + s);
    
                return s;
            } catch (LoginException le) {
                throw new InvalidCredentialException(le);
            } catch (IllegalArgumentException ile) {
                throw new InvalidCredentialException(ile);
            }

  • ObjectGridAuthorization

    客户机经过身份验证后,将从服务器返回 Subject 对象。此 Subject 可以用于对客户机访问进行授权。由于 ObjectGrid 提供 JAAS 授权现成支持,因此可以在 Java 策略文件或 JAAS 授权策略文件中定义 JAAS 授权策略。典型策略与以下所示类似:



    清单 2. JAAS 授权策略
                            
    grant codebase "http://www.ibm.com/com/ibm/ws/objectgrid/security/PrivilegedAction"
    principal com.tivoli.pd.jazn.PDPrincipal "manager1" {
        permission com.ibm.websphere.objectgrid.security.MapPermission 
        "Accounting.Balance",
        "read,write,insert";
    };

    此策略授予用户 manager1 对 Accounting ObjectGrid 的 Balance 映射的读取、写入和插入权限。

    JAAS 授权策略在纯文本文件中配置,这就使其管理起来有些麻烦。对于此示例,请使用 Access Manager 访问控制列表(Access Control List,ACL)来管理 ObjectGrid 授权策略。

    为了使用 Access Manager Authorization Server 授权 ObjectGrid 客户机访问,您需要实现 ObjectGridAuthorization 插件来进行 ObjectGrid 的自定义授权。为此目的创建了一个插件实现类:com.ibm.websphere.samples.objectgrid.security.tam.TAMOGAuthorization。清单 3 显示了演示如何针对 Subject 对象检查映射权限的代码。



    清单 3. TAMOGAuthorization. checkMapPermission(Subject, Permission) 方法代码示例
                            
    // The permission.getName() is the [OBJECTGRID_NAME].[MAP_NAME].
    // We convert it to the ACL object bt prefixing "/OGTAMSample"
    final PDPermission pdPerm = new PDPermission(resourcePath + permission.getName(), 
    	new String(pdPermissionStr));
    
    Set principals = subject.getPrincipals();
    
    Iterator iter = principals.iterator();
    while (iter.hasNext()) {
        try {
            PDPrincipal principal = (PDPrincipal) iter.next();
            if (principal.implies(pdPerm)) {
                return true;
            }
        } catch (ClassCastException cce) {
        }
    }
            
    return false;

    通过清单 3,我们了解到,可以首先构建 PDPermission 对象,用于表示 ObjectGrid 所需的权限,然后对 Subject 对象中的主体进行迭代。如果是 PDPrinciplal 对象,则将调用 implies 方法来检查其是否具有所需的权限。

运行示例应用程序

所有程序就位后,可以运行本文所包括的示例来了解 ObjectGrid 和 Access Manager 集成工作情况。下面的指令将帮助您设置环境和运行示例。

  1. 设置 Access Manager

    首先,您需要安装和设置 Access Manager。请使用 Access Manager V6.0 或更高版本。Access Manager 的详细安装和设置指令请参见参考资料部分,不过下面给出了您将需要执行的步骤的摘要列表:

    1. 安装 Access Manager Directory Server。
    2. 配置 Access Manager Directory Server。
    3. 安装 Access Manager Policy Server。
    4. 安装 Access Manager Authorization Server。
    5. 安装 Access Manager Runtime for Java system。
    6. 启动 Access Manager Directory Server。
    7. 启动 Access Manager Policy Server。
    8. 启动 Access Manager Authorization Server。
  2. 针对特定环境配置 Access Manager Runtime for Java

    您需要通过使用 pdjrtecfg 命令在您的系统上为 Java 组件 JRE 配置恰当的 Tivoli Access Manager Runtime。这将自动向 JRE 提供 Tivoli Access Manager 类和方法。选择希望配置的 JRE,并运行此命令:

    "c:\Program Files\Tivoli\Policy Director\sbin\pdjrtecfg.exe" -action config -host
     -port  -java_home c:\java142\jre
    

    其中:

    • 是 Access Manager Policy Server 主机名,例如:Localhost。
    • 是 Access Manager Policy Server 端口号,例如:7135。

    您将使用所配置的这个 JRE 来访问 Access Manager 运行时。

  3. 在安全域中配置 Java 应用程序

    使用 Access Manager 安全性的 Java 应用程序必须配置到 Tivoli Access Manager 安全域中。Access Manager 提供了名为 com.tivoli.pd.jcfg.SvrSslCfg 实用类,可用于完成必要的配置任务。请使用以下命令配置 Java 应用程序:

    java -classpath PD.jar com.tivoli.pd.jcfg.SvrSslCfg -action config -admin_id 
     -admin_pwd  -appsvr_id OGTAM 
    -appsvr_pwd passw0rd -host  -mode local -port 999 -policysvr  
    -authzsvr  -cfg_file  -key_file 
    -cfg_action create

    其中:

    • 是管理员 ID,缺省值为:sec_master。
    • 是管理员密码,缺省值为:secpw。
    • 是 Access Manager Policy Server 地址,例如:localhost:7135:1。
    • 是 Access Manager Authorization Server 地址,例如:localhost:7136:1。
    • 是配置文件的名称。
    • 是密钥存储文件的名称。
    • 是应用服务器的主机。缺省值为 localhost。
    成功配置 Tivoli Access Manager Java 应用服务器后,将允许应用程序对 Tivoli Access Manager 服务进行授权使用。
  4. 添加用户和 ACL

    在 Access Manager 中创建一些测试对象,如用户、组和受保护资源,然后添加访问控制列表策略。ACL 策略是一组规则(权限),用于指定在资源上执行特定操作所需的条件。ACL 策略控制可以在资源上执行哪些操作以及谁能够执行这些操作。对于本示例,操作是 ObjectGrid 映射权限,而资源是 ObjectGrid 映射名。

    启动 pdadmin 命令行(在 Windows® Start 菜单中名为 Administration 命令提示符)。使用 sec_master(密码为 passw0rd)登录后,运行清单 4 中的脚本(您可以复制并粘贴)。



    清单 4. 用于添加用户和 ACL PDAdmin 的脚本
                            
    // Create two groups employees and managers.
    group create employees "cn=employees,dc=ibm,dc=com" employees employees
    group create managers  "cn=managers,dc=ibm,dc=com"  managers  managers
    
    // Create user empoyee1, belonging to group employees
    // You need to have the dc=ibm,dc=com set up in the LDAP server. 
    user create employee1 uid=employee1,ou=people,dc=ibm,dc=com employee1 employee1 
    passw0rd
    	employees
    user modify employee1 account-valid yes
    
    // Create user manager1, belonging to group managers
    user create manager1  uid=manager1,ou=people,dc=ibm,dc=com manager1 manager1 
    passw0rd 
    	managers
    user modify manager1  account-valid yes
    
    // Create an object /OGTAMSample/Accounting.Balance which represents the 
    // Map Balance of ObjectGrid Accounting 
    
    objectspace create /OGTAMSample "Protected objectspace for ObjectGrid TAM integration
    	sample" 0
    object create /OGTAMSample/Accounting.Balance "ObjectGrid Accounting Map Balance 
    access
    	object" 0
    
    // create a "w" action to represent the ObjectGrid map write permission
    action create w write OG_Authzn
    
    // create an "i" action to represent the ObjectGrid map insert permission
    action create i insert OG_Authzn
    
    // create a "n" action to represent the ObjectGrid map invalidate permission
    action create n invalidate OG_Authzn
    
    // We use existing r action for ObjectGrid map read permission
    // We use existing d action for ObjectGrid map remove permission
    
    // Create an access control list
    acl create Balance_acl
    acl modify Balance_acl set description "ACL for ObjectGrid accounting Map Balance" 
    
    // Grant r, w, i, d, n actions to user manager1
    acl modify Balance_acl set user manager1 Trwidn
    
    // Grant only r and i actions to user employee1
    acl modify Balance_acl set user employee1 Tri
    
    
    // Attach the access control list to object /OGTamSample/Accounting.Balance 
    acl attach /OGTamSample/Accounting.Balance Balance_acl

    运行此脚本后,您就成功地创建并定义了用户能够在 ObjectGrid 映射中访问的权限。此脚本将用户 manager1 的操作设置为“Trwidn”,而这意味着用户 manager1 对 Balance 映射具有读取、写入、插入、删除和废除的权限。用户 employee1 的操作设置为“Tri”,这意味着 employee1 对 Balance 映射只具有读取和插入权限。

  5. 安装 ObjectGrid

    您将需要 J2SE ObjectGrid 安装来运行示例。如果未安装 ObjectGrid,请参见参考资料,可通过其中下载试用版。(请确保使用具有临时修复程序 PK52322 或更高版本的 WebSphere Extended Deployment Data Grid V6.1,并安装 [OBJECTGRID_HOME] 目录中的软件。)

  6. 运行示例

    在此示例中,您将启动安全 ObjectGrid 目录服务器和安全 ObjectGrid 容器服务器,然后您将执行客户机程序来访问存储在 ObjectGrid 容器服务器中的数据。为了启用 ObjectGrid 身份验证,您需要启用 ObjectGrid 客户机和服务器安全性:

    1. 将本文提供的 tamsample.zip 下载文件解压到 [OBJECTGRID_HOME] 目录中。您将在 tamsample 目录中看到以下文件:

      • tamSampleObjectgrid.xml:ObjectGrid 配置文件;此配置文件中定义了一个 Accounting ObjectGrid 和一个 Balance 映射。
      • objectGridDeployment.xml:ObjectGrid 部署策略文件控制如何部署 ObjectGrid。对于此示例,定义了最简单的部署策略:一个分区,没有副本。
      • client.props:ObjectGrid 客户机安全性配置文件。
      • objectGridSecurity.xml:ObjectGrid 集群安全性配置文件。
      • server.props:ObjectGrid 服务器特定的安全性配置文件。
      • tamsample.jar:包含集成插件实现类的 JAR 文件。
      • config.pd:JAAS 配置文件。

      有关这些属性文件的更多信息,请参见参考资料中提供的关于 ObjectGrid 安全性概述。

    2. 使用 Windows 或 UNIX® 相应的命令将 JAVA_HOME 设置为您在步骤 2 中配置的 JDK:

      对于 Windows:
                                      
      set JAVA_HOME=c:\java141\



      对于 UNIX:
                                      
      export JAVA_HOME=/java141/

    3. 在 [OBJECTGRID_HOME]/bin directory 中,运行相应的命令,以设置 ObjectGrid 环境:

      对于 Windows:
                                      
      setupCmdLine.bat



      对于 UNIX:
                                      
      ./setupCmdLine.s

    4. 在 [OBJECTGRID_HOME]/bin 目录中启动目录服务器。

    5. 使用下列一组命令来创建 startcatalog.bat/startcatalog.sh 脚本:

      对于 Windows:
                                      
      startOgServer.bat catalogServer -script. startcatalog.bat -clusterSecurityFile 
      ../tamsample/objectGridSecurity.xml -serverProps ../tamsample/server.props
      -jvmArgs 
      -classpath ../tamsample/tamsample.jar -Djava.security.auth.login.config=
      ../tamsample/config.pd



      对于 UNIX:
                                      
      ./startOgServer.sh catalogServer -script. startcatalog.sh -clusterSecurityFile 
      ../tamsample/objectGridSecurity.xml -serverProps ../tamsample/server.props 
      -jvmArgs 
      -classpath ../tamsample/tamsample.jar -Djava.security.auth.login.config=
      ../tamsample/config.pd

      -Djava.security.auth.login.config=../tamsample/config.pd JVM 选项设置 JAAS 登录配置文件。您还可以在 java.security 文件中使用 login.config.url.1=file:${OBJECTGRID_HOME}/tamsample/config.pd 对其进行设置。

    6. 启动目录服务器:

      对于 Windows:
                                      
      startcatalog.bat



      对于 UNIX:
                                      
      . startcatalog.sh &

    7. 在 [OBJECTGRID_HOME]/bin 目录中启动容器服务器。使用以下命令,以创建 startcontainer.bat/startcontainer.sh 脚本:

      对于 Windows:
                                      
      startOgServer.bat c0 -script. startcontainer.bat -objectGridFile 
      ../tamsample/tamSampleObjectgrid.xml -deploymentPolicyFile 
      ../tamsample/objectGridDeployment.xml -catalogServiceEndpoints 
      localhost:2809 -serverProps ../tamsample/server.props -jvmArgs
      -Djava.security.auth.login.config=../tamsample/config.pd



      对于 UNIX:
                                      
      ./startOgServer.sh c0 -script. startcontainer.sh -objectGridFile 
      ../xml/CSSelectorTestOG.xml -deploymentPolicyFile ../ 
      ../tamsample/objectGridDeployment.xml -catalogServiceEndpoints 
      localhost:2809 -serverProps ../tamsample/server.props  -jvmArgs 
      -Djava.security.auth.login.config=../tamsample/config.pd

    8. 运行此命令,以启动容器服务器:

      对于 Windows:
                                      
      startcontainer.bat



      对于 UNIX:
                                      
      . startcontainer.sh &

    9. 从 [OBJECTGRID_HOME] 目录启动客户机

      对于 Windows:
                                      
      java -cp lib/objectgrid.jar;tamsample/tamsample.jar;lib/mx4j.jar
      com.ibm.websphere.samples.objectgrid.security.tam.TAMOGClient 
      localhost:2809  



      对于 UNIX:
                                      
      java -cp lib/objectgrid.jar:tamsample/tamsample.jar:lib/mx4j.jar 
      com.ibm.websphere.samples.objectgrid.security.tam.TAMOGClient 
      localhost:2809  

      值是在之前步骤中使用 pdadmin 创建的用户 ID 和密码。如果您使用 JDK 5.0 或更高版本,则不需要将 mx4j.jar 放到类路径中。

    10. 使用 manager1 作为用户连接到服务器。以 Windows 为例,对应的命令将为:
      java -cp lib/objectgrid.jar;tamsample/tamsample.jar;lib/mx4j.jar 
      com.ibm.websphere.samples.objectgrid.security.tam.TAMOGClient 
      localhost:2809 manager1 passw0rd

      您将在命令窗口中看到与以下类似的输出:

      Insert user1 ...
      Get user1 ...
      user 1 has balance 10000.0
      Remove user1 ...

    11. 现在,使用 employee1 作为用户连接到服务器。以 Windows 为例,对应的命令将为:
      java -cp lib/objectgrid.jar;tamsample/tamsample.jar;lib/mx4j.jar 
      com.ibm.websphere.samples.objectgrid.security.tam.TAMOGClient 
      localhost:2809 employee1 passw0rd

      您将看到以下输出:

      Insert user1 ...
      Get user1 ...
      user 1 has balance 10000.0
      Remove user1 ...
      Exception in thread 
      "P=654937:O=0:CT" com.ibm.websphere.objectgrid.TransactionException: 
      rolling back transaction, see caused by exception
      .java:65)
      
      ... ...
      
      Caused by: 
      java.security.AccessControlException: The following access to the map 
      Accounting.Balance is not granted: com.
      ibm.websphere.objectgrid.security.MapPermission Accounting.Balance remove
              at com.ibm.ws.objectgrid.security.MapAuthorizer.
              getAccessControlException(MapAuthorizer.java:139)
      
      ... ...

      根异常消息为:

      java.security.AccessControlException: The following access to the map 
      Accounting.Balance is not granted: com.ibm.websphere.objectgrid.
      security.MapPermission Accounting.Balance remove.

      此消息表明用户 employee1 不具有删除 Accounting ObjectGrid 和 Balance 映射中的数据的权限。

 

结束语

本文描述了 ObjectGrid 身份验证和授权的基本流程,然后通过一个简单示例说明了 ObjectGrid 如何利用 Tivoli Access Manager 进行身份验证和授权。通过将 ObjectGrid 和 Tivoli Access Manager 集成,可提供安全的分布式缓存解决方案。访问 ObjectGrid Wiki,以获得关于 ObjectGrid 和 ObjectGrid 安全性的更多信息。

请使用浏览器的分享功能分享到微信等