登录(LoginController)¶
提供平台登录、注销、用户注册、找回密码、第三方免登(飞书/钉钉)、代理登录、调试登录、验证码与短信验证码、登录页多语言字段与企业域列表等能力。是 runtime 模块登录/认证域的核心控制器。
- 接口类型:REST 资源(
@RestController) - 基址:
${myapps.context-path.runtime:}(即 runtime context 根,端点路径各自独立,未统一加前缀) - Tag:登录模块
公共说明¶
- 响应结构(非统一 Resource):除
GET /、GET /api/login(HTTP 302 重定向)和POST /api/runtime/login/registerUser(返回裸字符串 token /"error")外,其余端点返回控制器私有的result(...)JSON 结构,字段名为resultCode/msg,而非统一 Resource 的errcode/errmsg:失败时{ "resultCode": "1", // "1"=成功,"0"=失败,个别端点用 "ok" "msg": "登陆成功", "<dataName1>": <任意>, // 动态业务字段(如 returnUrl、accessToken、checkcodeImg、multiLangWordList、result、domainList、userList、proxyUsers、status、data 等) "<dataName2>": <任意> }resultCode多为"0",msg为失败原因(可能含多语言占位符如{*[core.user.notexist]*})。 - 鉴权(据源码
RestSecurityHandlerInterceptor):拦截器仅注册到/api/runtime/**与/api/rest/bpm/**,并在内部按正则豁免以下路径—— /api/runtime/login.*(覆盖本控制器下/api/runtime/login/开头的全部端点,包括登录、注册、找回密码、验证码、多语言、企业域列表、代理登录、短信发送等)→ 豁免,无需 accessToken。/api/runtime/dingding/authlogin(钉钉免登)→ 豁免。/api/runtime/logout(退出登录)→ 不豁免,需通过 accessToken(query / header / Cookie 中任一)或 debugToken 标识用户。/api/debuglogin/**(4 个调试登录端点)与GET /、GET /api/login→ 不在拦截器覆盖范围,拦截器本身不校验;走通用 Servlet 过滤器链(RuntimeSecurityFilter等)。- 登录态令牌:登录成功后服务端通过
Security.generateToken(userId)生成 JWT,写入名为accessToken的 Cookie(调试登录写入debugTokenCookie);该 Cookie 也是后续受保护接口的凭证。 - 状态码:所有端点成功返回 HTTP 200;业务结果由响应体
resultCode体现,未与 HTTP 状态码绑定。
1. 访问主页面¶
访问 runtime 根路径时,将请求重定向到门户首页。
- 接口类型:REST 资源(HTTP 302 重定向)
- 请求方式:
GET - 请求路径:
/(完整:{runtime-context}/) - 鉴权:否(据源码:不在
RestSecurityHandlerInterceptor覆盖范围) - Tag:登录模块
请求参数¶
无。
请求示例¶
响应¶
结构:HTTP 302 重定向,Location: /static/portal/vue/index.html。无响应体。
2. 访问登录页面¶
重定向到前台登录页面。
- 接口类型:REST 资源(HTTP 302 重定向)
- 请求方式:
GET - 请求路径:
/api/login(完整:{runtime-context}/api/login) - 鉴权:否(据源码:不在
RestSecurityHandlerInterceptor覆盖范围) - Tag:登录模块
请求参数¶
无。
请求示例¶
响应¶
结构:HTTP 302 重定向,Location: signon/login.html。无响应体。
3. 飞书免登录¶
通过飞书免登授权码换取平台用户并完成登录,登录成功后返回前端跳转地址并写入 accessToken Cookie。
- 接口类型:REST 资源
- 请求方式:
POST - 请求路径:
/api/runtime/login/feisuhAuthLogin/domain/{domainId}/code/{code}(完整:{runtime-context}/api/runtime/login/feisuhAuthLogin/domain/{domainId}/code/{code}) - 鉴权:否(据源码:拦截器正则豁免
/api/runtime/login.*) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| domainId | path | string | 是 | 企业域Id |
| code | path | string | 是 | 飞书免登授权码 |
| loginway | query | string | 否 | 登录端标识;非空时跳转移动端首页(如 mobile) |
请求示例¶
响应¶
结构:私有 result JSON(见本页「公共说明 · 响应结构」)。
data 字段:url(前端跳转地址,PC 端默认 /static/portal/vue/index.html#/,移动端 /static/mobile/index.html#/)。用户不存在时返回 msg 提示并指向 url: /static/signon。
成功示例:
失败示例(用户不存在):
4. 获取登录页多语言字段¶
按语言获取登录页面所需的多语言文案集合,并把语言写入 userLanguage Cookie。
- 接口类型:REST 资源
- 请求方式:
POST - 请求路径:
/api/runtime/login/getMultiLangWordList(完整:{runtime-context}/api/runtime/login/getMultiLangWordList) - 鉴权:否(据源码:拦截器正则豁免
/api/runtime/login.*) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| jsonObj | body | object | 是 | 请求包体,须含 language 字段 |
请求体¶
请求示例¶
POST /api/runtime/login/getMultiLangWordList HTTP/1.1
Content-Type: application/json
{
"language": "CN"
}
响应¶
结构:私有 result JSON。
data 字段:multiLangWordList(Map),登录页各文案键值对(如 pageLoginAccount、pageLoginPassword、login、dingdingLogin、wechatLogin、scanCode 等)。
成功示例:
{
"resultCode": "1",
"msg": "成功",
"multiLangWordList": {
"pageLoginAccount": "账号",
"pageLoginPassword": "密码",
"login": "登录",
"dingdingLogin": "钉钉登录",
"wechatLogin": "微信登录"
}
}
失败示例:
5. 改变验证码¶
生成新的登录验证码图片,返回 Base64 编码的 JPG 图片字符串。
- 接口类型:REST 资源
- 请求方式:
POST - 请求路径:
/api/runtime/login/changeCheckcodeImg(完整:{runtime-context}/api/runtime/login/changeCheckcodeImg) - 鉴权:否(据源码:拦截器正则豁免
/api/runtime/login.*) - Tag:登录模块
请求参数¶
无。
请求示例¶
响应¶
结构:私有 result JSON。
data 字段:checkcode(string),格式为 data:image/jpg;base64,<Base64 字符串>,可直接作为 <img src> 使用。
成功示例:
{
"resultCode": "1",
"msg": "改变成功",
"checkcode": "data:image/jpg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRof..."
}
6. 获取企业域列表¶
返回所有启用状态的企业域名称列表、登录背景与密码加密方式,供登录页渲染。
- 接口类型:REST 资源
- 请求方式:
POST - 请求路径:
/api/runtime/login/getDomainList(完整:{runtime-context}/api/runtime/login/getDomainList) - 鉴权:否(据源码:拦截器正则豁免
/api/runtime/login.*) - Tag:登录模块
请求参数¶
无。
请求示例¶
响应¶
结构:私有 result JSON。
data 字段:result(object),含 domainList(企业域名称数组)、loginBackground(登录页背景资源路径)、encryptionMode(密码加密模式,默认 "0")。
成功示例:
{
"resultCode": "1",
"msg": "成功",
"result": {
"domainList": ["我的公司", "demo"],
"loginBackground": "/static/portal/images/login_bg.png",
"encryptionMode": "0"
}
}
失败示例:
7. 登录¶
使用企业域、账号、密码(密文)进行登录认证;成功后生成 accessToken 写入 Cookie 并返回跳转地址。
- 接口类型:REST 资源
- 请求方式:
POST - 请求路径:
/api/runtime/login/loginWithCiphertext2(完整:{runtime-context}/api/runtime/login/loginWithCiphertext2) - 鉴权:否(据源码:拦截器正则豁免
/api/runtime/login.*) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| jsonObj | body | object | 是 | 登录请求包体(字段见下) |
请求体¶
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| domainName | string | 是 | 企业域名称 |
| username | string | 是 | 登录账号 |
| password | string | 是 | 登录密码(密文)。客户端加密规则:将 BASE64(rp+lp) 中的后两位 rp 与前面 lp 互换位置后传输;服务端解码后再做比对 |
| remember | string | 否 | 是否记住登录(保留字段) |
| checkcode | string | 否 | 验证码(错误次数超阈值时必填) |
| language | string | 否 | 语言,默认 CN |
| debug | string | 否 | 调试标记(保留字段) |
{
"domainName": "我的公司",
"username": "admin",
"password": "00YWRtaW4=",
"remember": "0",
"language": "CN"
}
请求示例¶
POST /api/runtime/login/loginWithCiphertext2 HTTP/1.1
Content-Type: application/json
{
"domainName": "我的公司",
"username": "admin",
"password": "00YWRtaW4="
}
响应¶
结构:私有 result JSON。
data 字段:returnUrl(登录成功后的跳转地址,默认 ../signon/dispatcher.html;代理场景为 ../login/agent.html?id=<userId>)、checkcodeImg(验证码图片 Base64,需要时返回)、accessToken(登录成功后的访问令牌,同时写入 Cookie)。
业务校验:
- 企业域为空 → {*[cn.myapps.core.domain.label.name.illegal]*}
- 企业域不存在或禁用 → {*[core.domain.notexist]*}
- 用户不存在 → {*[core.user.notexist]*}
- 账号已锁定 → 该账号已锁定
- 密码已过期 → 密码已过期
- 密码错误累计计数(写入 SIGNON_LOGIN_CACHE_KEY 缓存)
成功示例:
{
"resultCode": "1",
"msg": "登陆成功",
"returnUrl": "../signon/dispatcher.html",
"checkcodeImg": "",
"accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Il9fWFhYWFhYIn0.xxxxxxxx"
}
失败示例:
8. 用户注册¶
通过手机号在企业域内注册新用户,注册成功后返回登录 token(裸字符串)。
- 接口类型:REST 资源
- 请求方式:
POST - 请求路径:
/api/runtime/login/registerUser(完整:{runtime-context}/api/runtime/login/registerUser) - 鉴权:否(据源码:拦截器正则豁免
/api/runtime/login.*) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| telephone | query | string | 是 | 手机号 |
| username | query | string | 是 | 登录账号 |
| password | query | string | 是 | 登录密码(明文) |
| domainName | query | string | 是 | 企业域名称 |
请求示例¶
POST /api/runtime/login/registerUser?telephone=13800000000&username=newuser&password=plain&domainName=%E6%88%91%E7%9A%84%E5%85%AC%E5%8F%B8 HTTP/1.1
响应¶
结构:裸字符串(非 JSON)。成功返回 token 字符串;失败返回字符串 "error"。
成功示例:
失败示例:
9. 找回密码¶
通过手机号(账号)重置登录密码。仅适用于账号为手机号的场景。
- 接口类型:REST 资源
- 请求方式:
POST - 请求路径:
/api/runtime/login/retrievePassword(完整:{runtime-context}/api/runtime/login/retrievePassword) - 鉴权:否(据源码:拦截器正则豁免
/api/runtime/login.*) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| telephone | query | string | 是 | 手机号(即登录账号) |
| password | query | string | 是 | 新密码(明文,服务端会加密入库) |
请求示例¶
响应¶
结构:私有 result JSON(resultCode 此处用 "ok")。
data 字段:status(始终为 null,结果看 msg)。
成功示例(重置成功):
失败示例(用户不存在):
10. 钉钉免登¶
通过钉钉免登授权码换取平台用户并完成登录,登录成功后返回带 accessToken 的前端跳转地址。
- 接口类型:REST 资源
- 请求方式:
GET - 请求路径:
/api/runtime/dingding/authlogin(完整:{runtime-context}/api/runtime/dingding/authlogin) - 鉴权:否(据源码:拦截器精确豁免
/api/runtime/dingding/authlogin) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| code | query | string | 是 | 钉钉免登授权码 |
| domainId | query | string | 是 | 企业域Id |
| appId | query | string | 否 | 软件(应用)Id;为 km 时跳转 KMS |
| formId | query | string | 否 | 表单Id;非空时跳转到对应待办详情 |
| docId | query | string | 否 | 文档Id;与 formId 配合使用 |
| isPc | query | boolean | 否 | 是否来自 PC 端,默认 false;决定跳转 PC 或移动门户 |
请求示例¶
GET /api/runtime/dingding/authlogin?code=__CODE__&domainId=__DOMAINID__&appId=__APPID__&isPc=true HTTP/1.1
响应¶
结构:私有 result JSON。
data 字段:returnUrl(前端跳转地址,URL 中已附带 accessToken 与其它上下文参数)。用户不存在时 resultCode=0,无 returnUrl。
成功示例:
{
"resultCode": "1",
"msg": "登陆成功",
"returnUrl": "/static/portal/vue/index.html?accessToken=eyJhbGciOiJIUzI1NiJ9..."
}
失败示例(用户不存在):
11. 获取可代理登录用户¶
根据当前用户Id,返回其可作为代理人登录的目标用户列表。
- 接口类型:REST 资源
- 请求方式:
GET - 请求路径:
/api/runtime/login/getProxyUsers/{userid}(完整:{runtime-context}/api/runtime/login/getProxyUsers/{userid}) - 鉴权:否(据源码:拦截器正则豁免
/api/runtime/login.*) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| userid | path | string | 是 | 代理人用户Id |
请求示例¶
响应¶
结构:私有 result JSON。
data 字段:proxyUsers(数组),元素为 { id, name, avatar };不在代理有效期内的用户被过滤。
成功示例:
{
"resultCode": "0",
"msg": "",
"returnUrl": "",
"proxyUsers": [
{ "id": "__UID1__", "name": "lisi", "avatar": "" },
{ "id": "__UID2__", "name": "wangwu", "avatar": "" }
]
}
说明:本端点
resultCode固定返回"0",结果应通过proxyUsers字段判断。
12. 代理登录¶
以代理身份登录到指定用户,写入新的 accessToken Cookie。
- 接口类型:REST 资源
- 请求方式:
GET - 请求路径:
/api/runtime/login/loginProxy/{userid}(完整:{runtime-context}/api/runtime/login/loginProxy/{userid}) - 鉴权:否(据源码:拦截器正则豁免
/api/runtime/login.*) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| userid | path | string | 是 | 被代理的目标用户Id |
请求示例¶
响应¶
结构:私有 result JSON。
data 字段:returnUrl(成功时为 ../signon/dispatcher.html,失败时为空字符串)。
成功示例:
失败示例:
13. 调试登录-获取企业域列表¶
调试登录场景下获取所有启用状态的企业域名称列表。
- 接口类型:REST 资源
- 请求方式:
GET - 请求路径:
/api/debuglogin/getDomainList(完整:{runtime-context}/api/debuglogin/getDomainList) - 鉴权:否(据源码:路径不在
RestSecurityHandlerInterceptor的/api/runtime/**覆盖范围) - Tag:登录模块
请求参数¶
无。
请求示例¶
响应¶
结构:私有 result JSON。
data 字段:domainList(企业域名称数组)。
成功示例:
失败示例:
14. 调试登录-获取用户列表¶
按企业域名称(及可选用户名前缀)模糊查询用户登录账号列表,供调试登录页选择。
- 接口类型:REST 资源
- 请求方式:
GET - 请求路径:
/api/debuglogin/getUserList(完整:{runtime-context}/api/debuglogin/getUserList) - 鉴权:否(据源码:路径不在
RestSecurityHandlerInterceptor的/api/runtime/**覆盖范围) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| domainName | query | string | 是 | 企业域名称 |
| username | query | string | 否 | 用户名模糊关键字,可空 |
请求示例¶
GET /api/debuglogin/getUserList?domainName=%E6%88%91%E7%9A%84%E5%85%AC%E5%8F%B8&username=admin HTTP/1.1
响应¶
结构:私有 result JSON。
data 字段:userList(用户登录账号字符串数组)。
成功示例:
失败示例:
15. 调试登录-获取多语言字段¶
调试登录场景下按语言获取登录页所需的多语言文案集合。
- 接口类型:REST 资源
- 请求方式:
GET - 请求路径:
/api/debuglogin/getMultiLangWordList(完整:{runtime-context}/api/debuglogin/getMultiLangWordList) - 鉴权:否(据源码:路径不在
RestSecurityHandlerInterceptor的/api/runtime/**覆盖范围) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| language | query | string | 是 | 语言标识,如 CN、EN、TW |
请求示例¶
响应¶
结构:私有 result JSON。
data 字段:multiLangWordList(Map),登录页各文案键值对。
成功示例:
{
"resultCode": "1",
"msg": "成功",
"multiLangWordList": {
"pageLoginAccount": "账号",
"pageLoginPassword": "密码",
"login": "登录"
}
}
失败示例:
16. 调试登录-登录¶
调试登录专用:按企业域 + 用户名直接登录(无需密码),生成的 token 写入 debugToken Cookie。
- 接口类型:REST 资源
- 请求方式:
POST - 请求路径:
/api/debuglogin/loginWithCiphertext2(完整:{runtime-context}/api/debuglogin/loginWithCiphertext2) - 鉴权:否(据源码:路径不在
RestSecurityHandlerInterceptor的/api/runtime/**覆盖范围) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| jsonObj | body | object | 是 | 调试登录请求包体 |
请求体¶
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| domainName | string | 是 | 企业域名称 |
| username | string | 是 | 登录账号;若含括号(多账号场景)取括号前部分 |
请求示例¶
POST /api/debuglogin/loginWithCiphertext2 HTTP/1.1
Content-Type: application/json
{
"domainName": "我的公司",
"username": "admin"
}
响应¶
结构:私有 result JSON。
data 字段:returnUrl(成功为 ../signon/dispatcher.html,代理场景为 ../login/agent.html?id=<userId>)、checkcodeImg(始终为空字符串)。
成功示例:
失败示例:
17. 退出登录¶
注销当前用户的登录态,记录注销日志(按企业域配置),并返回登出后的跳转地址。
- 接口类型:REST 资源
- 请求方式:
POST - 请求路径:
/api/runtime/logout(完整:{runtime-context}/api/runtime/logout) - 鉴权:是(据源码:拦截器覆盖
/api/runtime/**,且/api/runtime/logout不在豁免名单,需 accessToken 或 debugToken) - Tag:登录模块
请求参数¶
无(用户身份从请求中的 accessToken / debugToken 解析)。
请求示例¶
响应¶
结构:私有 result JSON(resultCode 此处用 "ok")。
data 字段:data(string),登出后的重定向地址;若认证类型为 SSO,返回配置的 SSO 登出地址,否则为空字符串。
成功示例:
18. 发送短信验证码¶
向指定用户的手机号发送短信验证码内容。
- 接口类型:REST 资源
- 请求方式:
POST - 请求路径:
/api/runtime/login/smsSend(完整:{runtime-context}/api/runtime/login/smsSend) - 鉴权:否(据源码:拦截器正则豁免
/api/runtime/login.*) - Tag:登录模块
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| userId | query/form | string | 是 | 接收短信的用户Id |
| content | query/form | string | 是 | 短信内容 |
说明:源码方法签名为
doSmsSend(String userId, String content),未显式标注@RequestParam,Spring 默认按名称绑定 query 与 form 参数均可。
请求示例¶
响应¶
结构:私有 result JSON(resultCode 此处用 "ok")。
data 字段:status(boolean),短信是否发送成功。
成功示例:
失败示例(内部异常被吞,仍返回 ok):