移动端登录(mobile.LoginController)¶
移动端用户登录接口:按企业域 + 账号 + 密码(支持 BASE64 编码回退)登录,登录成功后签发访问令牌(写入 Cookie)并返回用户基础信息。
范围说明:本控制器为移动端
cn.myapps.runtime.mobile.security.controller.LoginController,基址/runtime/app/security。另有同名页面级 REST 控制器cn.myapps.runtime.security.controller.LoginController(基址/,覆盖/api/runtime/login/**等),见 login.md,两者独立、不共用路由。
- 接口类型:REST 资源(
@Controller继承mobile.common.controller.BaseController,方法返回Map<String, Object>;源码未在该方法上声明@ResponseBody,且类级为@Controller而非@RestController,理论上 Spring MVC 会将返回的Map视为模型数据并尝试按请求 URL 解析视图。但据BaseController.addActionResult返回的dataMap结构与同包其他移动端控制器一致的「{status, message, data}JSON 响应」语义,配合前置RuntimeSecurityFilter与运行时 Jackson 视图解析配置,实际响应为 JSON 对象。本文档按源码语义记录为 REST 资源,并标注此注解缺失的异常。) - 基址:
${myapps.context-path.runtime:}/runtime/app/security - Tag:移动端登录(源码类级未声明
@Tag,按模块归并)
公共说明¶
- 鉴权(据源码):基址
/runtime/app/security不在RestSecurityHandlerInterceptor覆盖范围(拦截器仅覆盖/api/runtime/**与/api/rest/bpm/**)。鉴权由RuntimeMvcConfig注册的全局过滤器RuntimeSecurityFilter(URL 模式/*)执行。登录端点本身不需要 accessToken(这是登录入口,调用方尚无令牌);过滤器对未登录访问的拦截策略以运行时过滤器配置为准(移动端登录入口通常被纳入放行或 SSO 重定向白名单)。控制器内不读取accessToken,凭提交的企业域/账号/密码完成认证。 - 响应结构(据源码
mobile.common.controller.BaseController.addActionResult):本控制器端点返回Map<String, Object>,结构为: status:0成功,1失败;message:成功ok,失败error;data:业务数据;写入前由ESAPI.encode(data)做 XSS 编码。- 与统一
Resource(errcode/errmsg/data/errors)约定不一致,本文档按源码如实记录。 - 登录失败计数:失败次数缓存于
cacheManager的SIGNON_LOGIN_CACHE_KEY缓存(按用户登录号键),同一登录号连续失败超过 2 次后强制要求验证码(checkcode)。 - 设备 id 屏蔽:源码中「设备 id 不匹配」拦截逻辑已被注释,目前对
equipmentId不做强制校验;但若库内用户equipmentId为空且入参非空,则会把入参写回用户记录。
1. 用户登录¶
按企业域名 + 账号(或手机号回退)+ 密码完成登录;密码错误超过 2 次后需附验证码。成功后签发 access_token 并通过 SecurityCookie 写入响应 Cookie,返回用户基础信息(含令牌、用户 id、姓名、登录号、邮箱、手机、头像、企业域、默认部门等)。
- 接口类型:REST 资源
- 请求方式:
@RequestMapping(未限定 method,支持 GET / POST 等所有方法) - 请求路径:
/login.action(完整:{runtime-context}/runtime/app/security/login.action) - 鉴权:否(登录入口,不需要 accessToken;调用方提交凭据完成认证)
- Tag:移动端登录
请求参数¶
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| domainName | query | string | 是 | 企业域名称 |
| username | query | string | 是 | 登录号或手机号(按登录号查不到时回退为按手机号查) |
| password | query | string | 是 | 密码;首选按明文比对,失败后回退按 BASE64 解码再比对 |
| equipmentId | query | string | 是 | 设备 id(源码标注必填;当前未做强制校验,详见「公共说明 · 设备 id 屏蔽」) |
| checkcode | query | string | 是 | 验证码;仅当该账号密码错误次数 > 2 时强制校验(与 session 中的 Web.SESSION_ATTRIBUTE_CHECKCODE 比对,大小写不敏感);其余场景可省略 |
说明:源码
@Parameter对所有上述参数均标注required = true;实际语义以「说明」列为准(checkcode、equipmentId存在条件性)。
请求示例¶
POST /runtime/app/security/login.action HTTP/1.1
Content-Type: application/x-www-form-urlencoded
domainName=默认企业域&username=zhangsan&password=__PASSWORD__&equipmentId=__EQUIPID__
响应¶
结构:Map,固定字段见「公共说明 · 响应结构」。
data(成功):Map<String, String>,字段含 access_token、userId、username、loginno、email、mobile、mobile2、avatar(空为 "")、domain、department(默认部门 id),以及与 access_token 同值的 accessToken 字段(键名 Security.ACCESS_TOKEN)。
data(失败-需显示验证码):Map,仅含 { showCode: true },提示前端展示验证码输入。
data(失败-其他):空 JSONObject({})。
成功响应示例:
{
"status": 0,
"message": "ok",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"accessToken": "eyJhbGciOiJIUzI1NiJ9...",
"userId": "__USERID__",
"username": "张三",
"loginno": "zhangsan",
"email": "zhangsan@example.com",
"mobile": "13800000000",
"mobile2": "",
"avatar": "/uploads/avatar/zhangsan.png",
"domain": "默认企业域",
"department": "__DEPTID__"
}
}
失败响应示例(需验证码):
失败响应示例(其他):