|
| 1 | +# 阶段2:技术设计方案 |
| 2 | + |
| 3 | +## 1. 设计概述 |
| 4 | + |
| 5 | +### 1.1 设计目标 |
| 6 | +在现有登录拦截逻辑基础上进行增强,将登录来源判断方式从 request body 的 `source` 字段改为 HTTP Header 的 `webLogin` 字段。 |
| 7 | + |
| 8 | +### 1.2 设计原则 |
| 9 | +- **最小改动**: 复用现有拦截逻辑,仅修改来源判断方式 |
| 10 | +- **向后兼容**: 默认功能关闭,不影响现有系统 |
| 11 | +- **可配置性**: 支持配置开关和系统用户前缀列表 |
| 12 | + |
| 13 | +## 2. 架构设计 |
| 14 | + |
| 15 | +### 2.1 组件关系图 |
| 16 | + |
| 17 | +``` |
| 18 | +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ |
| 19 | +│ Web Frontend │────>│ Gateway Server │────>│ Backend API │ |
| 20 | +│ │ │ │ │ │ |
| 21 | +│ Header: │ │ UserRestful │ │ │ |
| 22 | +│ webLogin=true │ │ ↓ │ │ │ |
| 23 | +└─────────────────┘ │ tryLogin() │ └─────────────────┘ |
| 24 | + │ ↓ │ |
| 25 | + │ isWebLogin() │ |
| 26 | + │ ↓ │ |
| 27 | + │ checkSystemUser │ |
| 28 | + └─────────────────┘ |
| 29 | +``` |
| 30 | + |
| 31 | +### 2.2 处理流程 |
| 32 | + |
| 33 | +``` |
| 34 | +┌─────────────────────────────────────────────────────────────────┐ |
| 35 | +│ 登录请求处理流程 │ |
| 36 | +├─────────────────────────────────────────────────────────────────┤ |
| 37 | +│ │ |
| 38 | +│ ┌──────────┐ ┌───────────────┐ ┌────────────────────┐ │ |
| 39 | +│ │ 接收请求 │───>│ 获取用户名密码 │───>│ 检查功能开关是否开启 │ │ |
| 40 | +│ └──────────┘ └───────────────┘ └─────────┬──────────┘ │ |
| 41 | +│ │ │ |
| 42 | +│ ┌─────────────┴─────────────┐ │ |
| 43 | +│ │ 开关状态? │ │ |
| 44 | +│ └─────────────┬─────────────┘ │ |
| 45 | +│ 关闭 │ │ 开启 │ |
| 46 | +│ ▼ ▼ │ |
| 47 | +│ ┌─────────────┐ ┌─────────────────┐ │ |
| 48 | +│ │ 继续正常登录 │ │ 从Header获取 │ │ |
| 49 | +│ └─────────────┘ │ webLogin标识 │ │ |
| 50 | +│ └────────┬────────┘ │ |
| 51 | +│ │ │ |
| 52 | +│ ┌─────────────┴───────────┐ │ |
| 53 | +│ │ webLogin == "true"? │ │ |
| 54 | +│ └─────────────┬───────────┘ │ |
| 55 | +│ false │ │ true │ |
| 56 | +│ ▼ ▼ │ |
| 57 | +│ ┌─────────────┐ ┌───────────────┐ │ |
| 58 | +│ │ 继续正常登录 │ │ 检查用户名前缀 │ │ |
| 59 | +│ └─────────────┘ └───────┬───────┘ │ |
| 60 | +│ │ │ |
| 61 | +│ ┌───────────────┴─────────┐ │ |
| 62 | +│ │ 匹配系统用户前缀? │ │ |
| 63 | +│ └───────────────┬─────────┘ │ |
| 64 | +│ 否 │ │ 是 │ |
| 65 | +│ ▼ ▼ │ |
| 66 | +│ ┌─────────────┐ ┌─────────────┐ │ |
| 67 | +│ │ 继续正常登录 │ │ 返回错误信息 │ │ |
| 68 | +│ └─────────────┘ │ 拒绝登录 │ │ |
| 69 | +│ └─────────────┘ │ |
| 70 | +└─────────────────────────────────────────────────────────────────┘ |
| 71 | +``` |
| 72 | + |
| 73 | +## 3. 详细设计 |
| 74 | + |
| 75 | +### 3.1 配置项修改 |
| 76 | + |
| 77 | +**文件**: `GatewayConfiguration.scala` |
| 78 | + |
| 79 | +| 配置项 | 当前值 | 修改后 | |
| 80 | +|--------|--------|--------| |
| 81 | +| PROHIBIT_LOGIN_PREFIX | `hduser,shduser` | `hadoop,hduser,shduser` | |
| 82 | + |
| 83 | +**新增配置项**: 无需新增,复用现有配置 |
| 84 | + |
| 85 | +### 3.2 代码修改 |
| 86 | + |
| 87 | +**文件**: `UserRestful.scala` |
| 88 | + |
| 89 | +#### 3.2.1 新增方法: isWebLogin |
| 90 | + |
| 91 | +```scala |
| 92 | +private val WEB_LOGIN_HEADER = "webLogin" |
| 93 | + |
| 94 | +private def isWebLogin(gatewayContext: GatewayContext): Boolean = { |
| 95 | + val headers = gatewayContext.getRequest.getHeaders |
| 96 | + val webLoginValues = headers.get(WEB_LOGIN_HEADER) |
| 97 | + if (webLoginValues != null && webLoginValues.nonEmpty) { |
| 98 | + "true".equalsIgnoreCase(webLoginValues.head) |
| 99 | + } else { |
| 100 | + false // 默认为false |
| 101 | + } |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +#### 3.2.2 修改tryLogin方法 |
| 106 | + |
| 107 | +**现有代码**: |
| 108 | +```scala |
| 109 | +if ( |
| 110 | + GatewayConfiguration.PROHIBIT_LOGIN_SWITCH.getValue && |
| 111 | + (!getRequestSource(gatewayContext).equals("client")) |
| 112 | +) { |
| 113 | + PROHIBIT_LOGIN_PREFIX.split(",").foreach { prefix => |
| 114 | + if (userName.toLowerCase().startsWith(prefix)) { |
| 115 | + return Message.error("System users are prohibited from logging in(系统用户禁止登录)!") |
| 116 | + } |
| 117 | + } |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +**修改后**: |
| 122 | +```scala |
| 123 | +if ( |
| 124 | + GatewayConfiguration.PROHIBIT_LOGIN_SWITCH.getValue && |
| 125 | + isWebLogin(gatewayContext) |
| 126 | +) { |
| 127 | + PROHIBIT_LOGIN_PREFIX.split(",").foreach { prefix => |
| 128 | + if (userName.toLowerCase().startsWith(prefix)) { |
| 129 | + return Message.error("System users are prohibited from logging in(系统用户禁止登录)!") |
| 130 | + } |
| 131 | + } |
| 132 | +} |
| 133 | +``` |
| 134 | + |
| 135 | +## 4. 接口设计 |
| 136 | + |
| 137 | +### 4.1 登录接口变更 |
| 138 | + |
| 139 | +**接口**: POST /api/rest_j/v1/user/login |
| 140 | + |
| 141 | +**新增Header**: |
| 142 | +| Header | 类型 | 必填 | 默认值 | 说明 | |
| 143 | +|--------|------|------|--------|------| |
| 144 | +| webLogin | String | 否 | false | Web页面登录标识 | |
| 145 | + |
| 146 | +**请求示例**: |
| 147 | +```http |
| 148 | +POST /api/rest_j/v1/user/login HTTP/1.1 |
| 149 | +Host: gateway.linkis.com |
| 150 | +Content-Type: application/json |
| 151 | +webLogin: true |
| 152 | +
|
| 153 | +{ |
| 154 | + "userName": "testuser", |
| 155 | + "password": "xxx" |
| 156 | +} |
| 157 | +``` |
| 158 | + |
| 159 | +**错误响应** (系统用户被拦截): |
| 160 | +```json |
| 161 | +{ |
| 162 | + "method": "/api/rest_j/v1/user/login", |
| 163 | + "status": 1, |
| 164 | + "message": "System users are prohibited from logging in(系统用户禁止登录)!" |
| 165 | +} |
| 166 | +``` |
| 167 | + |
| 168 | +## 5. 前端配合要求 |
| 169 | + |
| 170 | +前端在Web页面调用登录接口时,需要在HTTP请求header中添加: |
| 171 | +```javascript |
| 172 | +headers: { |
| 173 | + 'webLogin': 'true' |
| 174 | +} |
| 175 | +``` |
| 176 | + |
| 177 | +## 6. 配置示例 |
| 178 | + |
| 179 | +### 6.1 linkis.properties |
| 180 | + |
| 181 | +```properties |
| 182 | +# 开启系统用户禁止登录功能 |
| 183 | +linkis.system.user.prohibit.login.switch=true |
| 184 | + |
| 185 | +# 系统用户前缀列表(逗号分隔) |
| 186 | +linkis.system.user.prohibit.login.prefix=hadoop,hduser,shduser |
| 187 | +``` |
| 188 | + |
| 189 | +## 7. 兼容性说明 |
| 190 | + |
| 191 | +| 场景 | 行为 | |
| 192 | +|------|------| |
| 193 | +| 旧前端(无webLogin header) | 默认webLogin=false,不拦截,正常登录 | |
| 194 | +| 客户端登录(无webLogin header) | 默认webLogin=false,不拦截,正常登录 | |
| 195 | +| 新前端(webLogin=true) + 普通用户 | 正常登录 | |
| 196 | +| 新前端(webLogin=true) + 系统用户 | 拦截,返回错误 | |
0 commit comments