第05章-安全配置与认证

第五章:安全配置与认证

5.1 引言

安全性是任何生产级应用的关键考虑因素,对于提供地理空间数据服务的 GeoServer Cloud 尤其重要。本章将全面介绍 GeoServer Cloud 的安全架构、认证机制和授权配置,帮助您构建安全可靠的地理空间服务平台。

GeoServer Cloud 继承了 GeoServer 强大的安全子系统,同时针对云原生部署环境进行了增强。我们将从基础的用户认证开始,逐步深入到企业级的 LDAP 集成、OAuth2 认证以及基于 ACL 的细粒度访问控制。

5.2 安全架构概述

5.2.1 安全组件层次

GeoServer Cloud 的安全架构分为多个层次:

┌─────────────────────────────────────────────────────────────────┐
│                        客户端请求                                │
└──────────────────────────────┬──────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                    Gateway (API 网关)                            │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  可选:集中式认证 / 速率限制 / WAF                        │    │
│  └─────────────────────────────────────────────────────────┘    │
└──────────────────────────────┬──────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                    GeoServer 安全过滤器链                        │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  认证过滤器 → 会话管理 → 授权决策 → 资源访问               │    │
│  └─────────────────────────────────────────────────────────┘    │
└──────────────────────────────┬──────────────────────────────────┘
                               │
        ┌──────────────────────┼──────────────────────┐
        │                      │                      │
        ▼                      ▼                      ▼
┌───────────────┐    ┌───────────────┐    ┌───────────────┐
│ 用户/角色存储  │    │  服务访问规则  │    │  数据访问规则  │
│  (XML/JDBC/   │    │  (WMS/WFS/    │    │  (图层/属性   │
│   LDAP)       │    │   REST)       │    │   级别)       │
└───────────────┘    └───────────────┘    └───────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                    GeoServer ACL (可选)                          │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  高级访问控制列表 - 基于规则的细粒度授权                    │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

5.2.2 认证方式

GeoServer Cloud 支持多种认证方式:

认证方式 说明 适用场景
HTTP Basic 基本用户名/密码认证 开发测试、内部API
Form 登录 Web 表单登录 WebUI 管理界面
API Key 基于 Key 的认证 应用程序集成
LDAP 目录服务认证 企业环境
OAuth2/OIDC 第三方身份提供商 单点登录
匿名访问 无需认证 公开数据服务

5.2.3 授权模型

GeoServer 使用基于角色的访问控制(RBAC):

用户 (User)
    │
    └── 拥有多个 ──▶ 角色 (Role)
                        │
                        └── 授予 ──▶ 权限 (Permission)
                                        │
                                        ├── 服务级别(WMS、WFS、REST)
                                        ├── 图层级别
                                        ├── 属性级别(字段)
                                        └── 空间范围(区域)

5.3 基础认证配置

5.3.1 默认安全配置

GeoServer Cloud 默认配置:

  • 管理员账户:admin / geoserver
  • 匿名用户可访问 OWS 服务(只读)
  • REST API 和 WebUI 需要认证

5.3.2 通过环境变量配置管理员

最简单的管理员配置方式:

services:
  wms:
    environment:
      - GEOSERVER_ADMIN_USERNAME=admin
      - GEOSERVER_ADMIN_PASSWORD=${ADMIN_PASSWORD}

这种方式的特点:

  • 在所有配置之前生效
  • 覆盖任何其他管理员配置
  • 如果使用非默认用户名,原 admin 用户会被禁用

5.3.3 用户管理(XML 存储)

默认情况下,用户存储在 XML 文件中。通过 WebUI 管理:

  1. 登录 GeoServer WebUI
  2. 导航到 安全 → 用户、组和角色
  3. 选择"用户"标签页

创建新用户

用户名: analyst
密码: ******
启用: ✓
角色: ROLE_AUTHENTICATED, DATA_ANALYST

用户属性存储位置

<!-- security/usergroup/default/users.xml -->
<userRegistry>
  <users>
    <user name="admin" password="digest1:..." enabled="true"/>
    <user name="analyst" password="digest1:..." enabled="true"/>
  </users>
  <groups/>
</userRegistry>

5.3.4 角色管理

内置角色

角色 说明
ROLE_ADMINISTRATOR 系统管理员,完全访问权限
ROLE_AUTHENTICATED 已认证用户
ROLE_ANONYMOUS 匿名用户

创建自定义角色

通过 WebUI 或 REST API:

curl -u admin:geoserver -X POST \
    -H "Content-Type: application/json" \
    -d '{"role":{"id":"DATA_ANALYST"}}' \
    "http://localhost:9090/geoserver/cloud/rest/security/roles/role/DATA_ANALYST"

5.3.5 服务访问规则

配置服务级别的访问控制:

# security/services.properties
# 格式:服务.操作=角色列表

# WMS 服务
wms.GetCapabilities=*
wms.GetMap=*
wms.GetFeatureInfo=ROLE_AUTHENTICATED

# WFS 服务
wfs.GetCapabilities=*
wfs.GetFeature=ROLE_AUTHENTICATED
wfs.Transaction=ROLE_EDITOR

# REST API
rest.GET=ROLE_AUTHENTICATED
rest.POST=ROLE_ADMINISTRATOR
rest.PUT=ROLE_ADMINISTRATOR
rest.DELETE=ROLE_ADMINISTRATOR

5.3.6 图层访问规则

配置图层级别的访问控制:

# security/layers.properties
# 格式:工作区.图层.权限=角色列表

# 全局默认规则
*.*.r=*
*.*.w=ROLE_AUTHENTICATED

# 特定图层规则
sensitive.classified.r=ROLE_CLASSIFIED_READ
sensitive.classified.w=ROLE_CLASSIFIED_WRITE

# 隐藏图层
secret.*.r=ROLE_SECRET_ACCESS

5.4 JDBC 安全存储

5.4.1 概述

JDBC 安全扩展允许将用户、组和角色存储在关系数据库中,适用于:

  • 大量用户管理
  • 与现有用户数据库集成
  • 需要程序化用户管理

5.4.2 配置 JDBC 安全

1. 创建数据库表

-- 用户表
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(128) NOT NULL UNIQUE,
    password VARCHAR(256) NOT NULL,
    enabled BOOLEAN DEFAULT TRUE
);

-- 角色表
CREATE TABLE roles (
    id SERIAL PRIMARY KEY,
    rolename VARCHAR(64) NOT NULL UNIQUE
);

-- 用户角色关联表
CREATE TABLE user_roles (
    user_id INTEGER REFERENCES users(id),
    role_id INTEGER REFERENCES roles(id),
    PRIMARY KEY (user_id, role_id)
);

-- 组表
CREATE TABLE groups (
    id SERIAL PRIMARY KEY,
    groupname VARCHAR(128) NOT NULL UNIQUE,
    enabled BOOLEAN DEFAULT TRUE
);

-- 用户组关联表
CREATE TABLE user_groups (
    user_id INTEGER REFERENCES users(id),
    group_id INTEGER REFERENCES groups(id),
    PRIMARY KEY (user_id, group_id)
);

-- 组角色关联表
CREATE TABLE group_roles (
    group_id INTEGER REFERENCES groups(id),
    role_id INTEGER REFERENCES roles(id),
    PRIMARY KEY (group_id, role_id)
);

2. 配置 JNDI 数据源

jndi:
  datasources:
    usersdb:
      enabled: true
      url: jdbc:postgresql://localhost:5432/users
      username: geoserver
      password: ${USERS_DB_PASSWORD}

3. 配置 JDBC 用户组服务

通过 WebUI 配置:

  1. 安全 → 用户、组和角色
  2. 添加新的用户组服务
  3. 选择 JDBC 类型
  4. 配置数据源和 SQL 查询

5.4.3 自定义 SQL 查询

# 用户查询
users-by-username-sql: >
  SELECT username, password, enabled 
  FROM users WHERE username = ?

# 角色查询
roles-by-username-sql: >
  SELECT r.rolename 
  FROM roles r 
  JOIN user_roles ur ON r.id = ur.role_id 
  JOIN users u ON ur.user_id = u.id 
  WHERE u.username = ?

# 组角色查询
roles-by-group-sql: >
  SELECT r.rolename 
  FROM roles r 
  JOIN group_roles gr ON r.id = gr.role_id 
  JOIN groups g ON gr.group_id = g.id 
  WHERE g.groupname = ?

5.5 LDAP 认证集成

5.5.1 概述

LDAP(轻量级目录访问协议)集成允许使用企业目录服务进行认证,常见的 LDAP 服务器:

  • Microsoft Active Directory
  • OpenLDAP
  • Apache Directory Server
  • 389 Directory Server

5.5.2 基本 LDAP 配置

1. 配置 LDAP 认证提供者

通过 WebUI:安全 → 认证 → 添加新的认证提供者

# LDAP 服务器配置
ldap:
  server:
    url: ldap://ldap.example.com:389
    base-dn: dc=example,dc=com
  # 绑定凭据(用于搜索用户)
  bind:
    dn: cn=geoserver,ou=services,dc=example,dc=com
    password: ${LDAP_BIND_PASSWORD}
  # 用户搜索
  user:
    search-base: ou=users
    search-filter: (uid={0})
  # 组搜索
  group:
    search-base: ou=groups
    search-filter: (member={0})
    role-attribute: cn

2. Active Directory 特定配置

ldap:
  server:
    url: ldap://ad.example.com:389
    base-dn: dc=example,dc=com
  bind:
    dn: CN=GeoServer Service,OU=Services,DC=example,DC=com
    password: ${AD_BIND_PASSWORD}
  user:
    search-base: OU=Users
    search-filter: (sAMAccountName={0})
  group:
    search-base: OU=Groups
    search-filter: (member={0})
    role-attribute: cn

5.5.3 LDAP 角色映射

将 LDAP 组映射到 GeoServer 角色:

# LDAP 组 → GeoServer 角色映射
LDAP Group: cn=GIS_Admins,ou=groups,dc=example,dc=com
GeoServer Role: ROLE_ADMINISTRATOR

LDAP Group: cn=GIS_Editors,ou=groups,dc=example,dc=com
GeoServer Role: ROLE_EDITOR

LDAP Group: cn=GIS_Viewers,ou=groups,dc=example,dc=com
GeoServer Role: ROLE_AUTHENTICATED

5.5.4 LDAPS 安全连接

使用 SSL/TLS 保护 LDAP 连接:

ldap:
  server:
    url: ldaps://ldap.example.com:636
    # 或使用 StartTLS
    # url: ldap://ldap.example.com:389
    # use-start-tls: true
  ssl:
    # 信任存储配置
    trust-store: /etc/ssl/ldap-truststore.jks
    trust-store-password: ${LDAP_TRUSTSTORE_PASSWORD}

5.6 OAuth2 / OpenID Connect

5.6.1 概述

OAuth2 和 OpenID Connect (OIDC) 支持与第三方身份提供商集成,实现单点登录(SSO):

  • Google
  • GitHub
  • Azure AD
  • Keycloak
  • Okta
  • Auth0

5.6.2 配置 OAuth2

使用 geOrchestra Gateway

GeoServer Cloud 推荐使用 geOrchestra Gateway 实现 OAuth2 认证:

services:
  gateway:
    image: georchestra/gateway:latest
    environment:
      - SPRING_PROFILES_ACTIVE=oauth2
      - OAUTH2_CLIENT_ID=${OAUTH2_CLIENT_ID}
      - OAUTH2_CLIENT_SECRET=${OAUTH2_CLIENT_SECRET}
      - OAUTH2_AUTHORIZATION_URI=https://auth.example.com/authorize
      - OAUTH2_TOKEN_URI=https://auth.example.com/token
      - OAUTH2_USER_INFO_URI=https://auth.example.com/userinfo

5.6.3 Keycloak 集成示例

1. Keycloak 配置

在 Keycloak 中创建客户端:

  • Client ID: geoserver-cloud
  • Client Protocol: openid-connect
  • Access Type: confidential
  • Valid Redirect URIs: http://localhost:9090/*

2. GeoServer Cloud 配置

spring:
  security:
    oauth2:
      client:
        registration:
          keycloak:
            client-id: geoserver-cloud
            client-secret: ${KEYCLOAK_CLIENT_SECRET}
            scope: openid,profile,email,roles
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
        provider:
          keycloak:
            issuer-uri: https://keycloak.example.com/realms/geoserver
            user-name-attribute: preferred_username

5.6.4 角色映射

从 OAuth2 令牌中提取角色:

geoserver:
  security:
    oauth2:
      role-mapping:
        enabled: true
        # JWT claim 路径
        claim-path: realm_access.roles
        # 角色前缀
        role-prefix: ROLE_
        # 角色名称映射
        mappings:
          gis-admin: ADMINISTRATOR
          gis-editor: EDITOR
          gis-user: AUTHENTICATED

5.7 GeoServer ACL 访问控制

5.7.1 概述

GeoServer ACL 是一个高级授权系统,提供比默认安全子系统更细粒度的访问控制:

  • 基于规则的访问控制
  • 空间范围限制
  • 属性过滤
  • 请求限制

5.7.2 部署 GeoServer ACL

添加 ACL 服务到部署

services:
  acl:
    image: geoservercloud/geoserver-acl:${TAG}
    environment:
      - SPRING_PROFILES_ACTIVE=pgconfig
      - PGCONFIG_HOST=database
      - PGCONFIG_DATABASE=geoserver_acl
    depends_on:
      - database

  wms:
    environment:
      - SPRING_PROFILES_ACTIVE=pgconfig,acl
      - GEOSERVER_ACL_ENABLED=true
      - GEOSERVER_ACL_URL=http://acl:8080

5.7.3 ACL 规则配置

规则结构

{
  "priority": 1,
  "access": "ALLOW",
  "role": "ROLE_ANALYST",
  "service": "WFS",
  "request": "GetFeature",
  "workspace": "analytics",
  "layer": "sales_data",
  "attributes": {
    "include": ["id", "region", "amount"],
    "exclude": ["customer_ssn"]
  },
  "spatialFilter": {
    "type": "INTERSECTS",
    "geometry": {
      "type": "Polygon",
      "coordinates": [[[...], ...]]
    }
  }
}

通过 REST API 管理规则

# 创建规则
curl -u admin:geoserver -X POST \
    -H "Content-Type: application/json" \
    -d '{
      "priority": 10,
      "access": "ALLOW",
      "role": "ROLE_DATA_VIEWER",
      "service": "WMS",
      "workspace": "*",
      "layer": "*"
    }' \
    "http://localhost:8080/acl/api/rules"

# 列出所有规则
curl -u admin:geoserver \
    "http://localhost:8080/acl/api/rules"

5.7.4 空间访问限制

限制用户只能访问特定地理范围的数据:

{
  "priority": 5,
  "access": "LIMIT",
  "role": "ROLE_REGION_NORTH",
  "service": "*",
  "layer": "all_regions",
  "spatialFilter": {
    "type": "INTERSECTS",
    "crs": "EPSG:4326",
    "geometry": {
      "type": "Polygon",
      "coordinates": [[
        [-180, 45], [180, 45], [180, 90], [-180, 90], [-180, 45]
      ]]
    }
  }
}

5.7.5 属性级别访问控制

限制用户可以访问的字段:

{
  "priority": 8,
  "access": "ALLOW",
  "role": "ROLE_PUBLIC_USER",
  "service": "WFS",
  "layer": "parcels",
  "attributes": {
    "include": ["id", "address", "area"],
    "exclude": ["owner_name", "tax_value", "ssn"]
  }
}

5.8 API Key 认证

5.8.1 配置 API Key 认证

启用 Key Authentication 扩展:

geoserver:
  security:
    auth-key:
      enabled: true
      # 认证提供者类型
      provider: property-file  # 或 user-property, web-service
      # 请求参数名
      parameter-name: apikey
      # 请求头名
      header-name: X-API-Key

5.8.2 API Key 存储方式

属性文件方式

# security/authkey/keys.properties
# 格式:apikey=username

abc123def456=user1
xyz789uvw012=user2

用户属性方式

每个用户可以有自己的 API Key,存储在用户属性中:

<user name="user1" password="...">
  <property name="apikey" value="abc123def456"/>
</user>

5.8.3 使用 API Key

# 通过查询参数
curl "http://localhost:9090/geoserver/cloud/wms?apikey=abc123def456&service=WMS&request=GetCapabilities"

# 通过请求头
curl -H "X-API-Key: abc123def456" \
    "http://localhost:9090/geoserver/cloud/wms?service=WMS&request=GetCapabilities"

5.9 安全最佳实践

5.9.1 密码策略

配置强密码策略:

geoserver:
  security:
    password:
      # 最小长度
      min-length: 12
      # 必须包含
      require-uppercase: true
      require-lowercase: true
      require-digit: true
      require-special: true
      # 密码过期
      max-age-days: 90
      # 禁止重复使用
      history-count: 5

5.9.2 会话管理

server:
  servlet:
    session:
      timeout: 30m  # 会话超时
      cookie:
        secure: true  # 仅 HTTPS
        http-only: true  # 防止 XSS
        same-site: strict  # CSRF 保护

5.9.3 HTTPS 配置

生产环境必须使用 HTTPS:

在 Gateway 配置 SSL

server:
  ssl:
    enabled: true
    key-store: /etc/ssl/keystore.p12
    key-store-password: ${SSL_KEYSTORE_PASSWORD}
    key-store-type: PKCS12
    key-alias: gateway

或使用反向代理(推荐)

# Nginx 配置
server {
    listen 443 ssl http2;
    server_name geoserver.example.com;
    
    ssl_certificate /etc/ssl/certs/geoserver.crt;
    ssl_certificate_key /etc/ssl/private/geoserver.key;
    
    location / {
        proxy_pass http://gateway:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

5.9.4 请求限制

在 Gateway 配置请求速率限制:

spring:
  cloud:
    gateway:
      filter:
        request-rate-limiter:
          enabled: true
      routes:
        - id: wms
          uri: lb://wms-service
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200
                key-resolver: "#{@userKeyResolver}"

5.9.5 审计日志

启用安全审计日志:

logging:
  level:
    org.geoserver.security: INFO
    org.springframework.security: INFO
    
geoserver:
  security:
    audit:
      enabled: true
      log-successful: true
      log-failed: true

5.10 故障排除

5.10.1 常见安全问题

问题:认证失败

# 检查用户是否存在
curl -u admin:geoserver \
    "http://localhost:9090/geoserver/cloud/rest/security/usergroup/users.json"

# 检查认证过滤器链
curl -u admin:geoserver \
    "http://localhost:9090/geoserver/cloud/rest/security/auth/chains.json"

问题:授权被拒绝

# 检查用户角色
curl -u admin:geoserver \
    "http://localhost:9090/geoserver/cloud/rest/security/roles/user/analyst.json"

# 检查访问规则
cat security/layers.properties
cat security/services.properties

5.10.2 LDAP 连接问题

# 测试 LDAP 连接
ldapsearch -x -H ldap://ldap.example.com:389 \
    -D "cn=geoserver,ou=services,dc=example,dc=com" \
    -W -b "dc=example,dc=com" "(uid=testuser)"

# 检查证书(LDAPS)
openssl s_client -connect ldap.example.com:636

5.11 本章小结

本章全面介绍了 GeoServer Cloud 的安全配置:

  1. 安全架构:了解了多层安全架构和认证授权模型。

  2. 基础认证:配置了用户、角色和访问规则。

  3. JDBC 存储:将安全数据存储在关系数据库中。

  4. LDAP 集成:与企业目录服务集成。

  5. OAuth2/OIDC:实现单点登录。

  6. GeoServer ACL:配置细粒度的访问控制。

  7. API Key:为应用程序提供简化的认证方式。

  8. 最佳实践:密码策略、会话管理、HTTPS 配置等。

在下一章中,我们将学习如何使用 Docker Compose 进行生产级部署。

5.12 思考题

  1. 在什么场景下应该使用 LDAP 认证而不是本地用户存储?

  2. GeoServer ACL 与默认的访问规则有什么区别?什么时候需要使用 ACL?

  3. 如何设计一个支持多租户的安全方案,确保租户间的数据隔离?

  4. OAuth2 的 authorization_code 流程与 client_credentials 流程有什么区别?各适用于什么场景?

  5. 在高安全要求的环境中,应该采取哪些额外的安全措施?

posted @ 2025-11-29 13:07  我才是银古  阅读(0)  评论(0)    收藏  举报