跳转至

移动端登录(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,
      "message": "ok",
      "data": <数据>
    }
    
  • status0 成功,1 失败;
  • message:成功 ok,失败 error
  • data:业务数据;写入前由 ESAPI.encode(data) 做 XSS 编码。
  • 与统一 Resourceerrcode/errmsg/data/errors)约定不一致,本文档按源码如实记录。
  • 登录失败计数:失败次数缓存于 cacheManagerSIGNON_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;实际语义以「说明」列为准(checkcodeequipmentId 存在条件性)。

请求示例

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_tokenuserIdusernameloginnoemailmobilemobile2avatar(空为 "")、domaindepartment(默认部门 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__"
  }
}

失败响应示例(需验证码):

{ "status": 1, "message": "error", "data": { "showCode": true } }

失败响应示例(其他):

{ "status": 1, "message": "error", "data": {} }