外观
登录与账号
字数
6727 字
预计阅读
26 分钟
这一页讲用户怎样登录、怎样管理自己的账号,以及管理员能控制哪些规则。大部分规则都是参数(管理员在后台修改、立即生效的配置),在 系统管理 → 参数设置 中修改,所有键名和默认值汇总在相关参数。
默认状态
开箱即用的只有账号密码登录,并且默认开启滑块验证码。短信登录要先配置短信渠道;注册和微信小程序登录默认关闭。
登录方式
| 方式 | 在哪里用 | 默认 | 前提 |
|---|---|---|---|
| 账号密码 | 电脑端、手机端 | 开启 | 无 |
| 短信验证码 | 电脑端、手机端 | 页面上有入口,配置短信后才能收到验证码 | 配置短信渠道;用户资料里填了手机号 |
| 微信小程序 | 只在微信小程序里 | 关闭 | 见微信小程序登录 |
登录成功后回到登录前想打开的页面(只允许本站的地址)。首页会显示你上次登录的时间,发现不是自己登录的,可以马上改密码。
用这里的账号登录别的系统
别的系统(第三方应用)也可以让用户用本系统的账号登录(单点登录,OAuth2):第三方应用把用户带到本系统的授权页,没登录的先在这里登录,同意授权后回到第三方应用。管理员先要在 系统管理 → 客户端管理 中登记这个应用,见单点登录(OAuth2)。
账号密码登录
登录页的"密码登录"标签:填写用户名和密码,下面有三个选项:
用户名不存在、用户已停用、密码错误时,提示都是同一句"用户名或密码错误",响应时间也一样,别人无法借此判断某个账号是否存在。真实原因只记在登录日志里。
短信登录
登录页的"短信登录"标签:填写手机号,点"获取验证码",收到后填写 6 位验证码登录,同样可以勾选"保持登录"。
要使用短信,管理员先要:
- 在 系统管理 → 消息中心 → 短信渠道 中新增一个启用的渠道。支持阿里云、腾讯云,还有一个调试模式(只把短信内容写进服务端日志,不真正发送,适合开发时使用);
- 在 系统管理 → 消息中心 → 短信模板 中,给编码为
auth.sms_code的验证码模板选择这个渠道,并保持模板启用。
验证码的规则:
- 6 位数字,5 分钟内有效;
- 每条验证码最多输错 5 次,之后作废;重新获取后,之前没用过的验证码都会作废;
- 同一个手机号 60 秒内只能获取一次,每天最多 10 次;同一个 IP 每天最多 20 次;全站每天最多 1000 条(都可以在参数中修改);
- 不论手机号有没有对应的账号,页面上的提示都一样("若该手机号已关联账号,验证码将稍后送达"),但只有属于启用用户的号码才会真的收到短信。
手机号从哪里来
短信登录按用户资料里的手机号找账号。管理员可以在 系统管理 → 用户管理 中填写,用户也可以在个人中心更换手机号。
手机端
移动端(uni-app 开发的员工手机端,包括安卓、iOS 和微信小程序)的登录页同样支持账号密码和短信验证码两种方式,并且总是"保持登录"。在微信小程序里还可以用微信登录。
验证码
验证码用来挡住自动化的批量尝试。参数 captcha.mode 决定使用哪一种:
| 值 | 效果 |
|---|---|
slider(默认) | 滑块:把拼图块拖到缺口的位置 |
image | 图形:看图填写答案 |
off | 关闭(失败过多时仍会强制出现,见下文) |
图形验证码有两种题型,由参数 captcha.image_type 决定:math(默认,一位数的加、减、乘法算术题)或 chars(4 个字符,不区分大小写,已经去掉容易看错的字符)。
什么时候出现:模式不是 off 时,下面这些操作之前会先弹出验证码:
- 账号密码登录;
- 注册;
- 获取短信验证码(短信登录、找回密码,以及小程序里的绑定)。
另外,同一个用户名一小时内在所有 IP 上累计失败 auth.cross_ip_threshold 次(默认 10 次)后,即使模式是 off,登录这个用户名时也会要求验证码(这时出现的是图形验证码)。
每道验证码 2 分钟内有效,只能作答一次,答错要换一道新的。通过后得到的凭证同样 2 分钟内有效、只能用一次,并且只能用于同一个 IP 上的同一种操作。修改参数后立即生效,页面每次使用时都会重新读取模式。
注册
注册默认关闭。把参数 auth.signup.enabled 改为 true 后,登录页下方出现"创建账号"链接。
- 注册时填写用户名、密码和显示名称(选填,不填时等于用户名)。用户名只能使用字母、数字和
_.@-,最多 64 个字符,已被占用时会提示; - 新用户自动获得参数
auth.signup.default_role_id指定的角色。初始化数据时,它被设为预置的"注册成员"角色(普通角色,不是内置角色):数据范围是"仅本人",只能看到首页; - 参数
auth.signup.default_dept_id可以指定新用户的部门,留空表示不分配部门; - 注册成功后回到登录页,用新账号登录。注册时设置的密码不需要再改。
默认角色有安全限制
默认角色不存在、已停用、是超级管理员或其他内置角色、或者数据范围是"全部数据"时,注册会被拒绝(提示"当前不开放注册")。这样即使参数填错了,也不会让陌生人注册出一个高权限账号。
找回密码
登录页的"忘记密码?"进入找回密码页:填写手机号,获取短信验证码,再设置新密码(必须符合密码策略)。
- 前提和短信登录一样:已经配置短信,并且账号资料里有这个手机号;
- 重设成功后,这个账号在所有设备上的登录都会失效,微信小程序绑定也会解除,然后用新密码重新登录;
- 用这种方式设置的密码不需要再改。
密码
密码策略
密码要满足的规则(前端和服务端用同一套规则检查):
| 规则 | 参数 | 默认 |
|---|---|---|
| 最小长度 | iam.password_min_length | 8 个字符(可设为 8–72) |
| 至少包含几类字符:小写字母、大写字母、数字、符号 | iam.password_char_classes | 2 类(可设为 0–4) |
| 最大长度 | 固定 | 72 个字节(一个汉字算 3 个字节) |
| 新密码不能和旧密码相同 | 固定 | 只在修改密码时检查 |
修改密码、找回密码、注册,以及管理员新建用户、重置密码时都会检查这些规则。修改策略不影响已经设置好的密码,只对之后的新密码生效。
首次登录强制改密
管理员新建的用户、被管理员重置过密码的用户,以及初始化数据时随机生成密码的 admin(没有设置环境变量 SEED_ADMIN_PASSWORD 时),第一次登录时必须先修改密码。这时只会进入修改密码页,页面上说明原因,并提供"退出登录"按钮;改完密码之前,其他所有操作都会被服务端拒绝(提示"请先修改密码")。
密码过期
参数 iam.password_expire_days 设为大于 0 的天数后,密码用了这么多天就会过期。过期的用户下次登录时同样只能先改密码,页面提示"密码已过期,请修改密码后继续使用"。默认值 0 表示永不过期。
登录失败锁定
用户能感受到的规则:
- 同一个用户名在同一个 IP 上连续失败
auth.lock_threshold次(默认 5 次),这个用户名在这个 IP 上锁定auth.lock_minutes分钟(默认 10 分钟,从最后一次失败开始算),提示"登录失败次数过多,请稍后再试"; - 只锁"用户名 + IP"这一对组合:同一个人在其他地方仍然可以登录,别人也没法故意输错把你的账号锁死;
- 同一个用户名在所有 IP 上一小时内累计失败太多次,之后登录要先过验证码,见验证码;
- 登录成功后失败次数清零;管理员也可以在登录日志里用"解锁账户"立即解除锁定,见登录日志;
- 参数
auth.ip_blacklist是登录 IP 黑名单。填写 IP 地址或网段(比如192.168.1.0/24),多个之间用逗号、空格或换行分隔,写错的条目会被忽略。黑名单中的 IP 无论用哪种方式都不能登录,提示"当前 IP 已被禁止访问"。
已经登录后再输入当前密码(锁屏解锁、修改密码、更换手机号)时,三处共用一个计数:连续输错 auth.lock_threshold 次后,这个账号在所有设备上的登录都会失效,需要重新登录。这样即使有人拿到了一台没锁好的电脑,也不能无限次地猜密码。
更多防护细节见安全基线 · 登录防护。
会话时长
会话就是"一次登录":在一个浏览器或者一部手机上登录一次,就产生一个会话,退出登录时结束。
| 情况 | 什么时候需要重新登录 |
|---|---|
| 没有勾选"保持登录" | 关掉浏览器后;或者从登录时算起满 12 小时 |
| 勾选了"保持登录" | 从登录时算起满 7 天 |
| 手机端(App、小程序) | 从登录时算起满 7 天 |
| 第三方应用(单点登录) | 由这个应用的客户端设置决定,最长 30 天,从第三方应用换到令牌时算起,见单点登录 · 会话和令牌 |
12 小时和 7 天是上限,不会因为一直在使用而延长。
在这个范围内,用户通常感觉不到令牌的存在:访问令牌(每次请求都带上的通行证)默认 30 分钟有效,过期后前端会自动换一个新的,然后重发刚才的请求。只有服务端拒绝换新时(比如会话到了上限,或者在别处修改了密码),才会弹出"会话已过期"对话框,可以选择留在本页保留没保存的内容,或者重新登录后回到这个页面。换新时服务端暂时连不上,不算会话结束,见下一节。
两个时长可以用环境变量调整:ACCESS_TTL_SEC(访问令牌,默认 1800 秒)和 REFRESH_TTL_SEC(刷新令牌,默认 604800 秒,即 7 天),见环境变量。12 小时和 7 天的上限是固定的。
修改密码、被停用、被强制下线等情况下会话怎样失效,见安全基线 · 认证与会话。修改或重置密码、被停用或删除、被管理员"强退该用户"时,这个用户授权给第三方应用的会话也一起结束。
服务重启或部署时
服务端重启或者发布新版本的那一会儿,电脑端不会把用户赶回登录页:
- 打开或刷新页面时,前端要先换访问令牌、读取用户信息和菜单。这时服务端没有响应、返回 429(请求太多)或 5xx(服务端错误),前端会自动重试,间隔逐渐拉长,总共大约 20 秒;
- 20 秒后还是不行,进入 503 页面,显示"服务器暂时无法连接,请稍后重试",下面有"重试"和"登录"两个按钮。"重试"回到原来要打开的页面再试一次;
- 只有服务端明确拒绝了换新(401,比如会话已经结束),或者这个浏览器上本来就没有登录,才进入登录页;
- 已经打开的页面上,换新令牌时服务端连不上,只提示"网络异常,请稍后重试",不弹"会话已过期",页面和没保存的内容都在。重新操作一次即可;
- 很多请求一起失败时,同一句错误提示只显示一条,旁边显示重复的次数。
锁定屏幕
暂时离开电脑时,点右上角用户菜单里的锁定屏幕。页面切换为锁屏页,要输入自己的密码才能解锁回到原来的页面:
- 刷新页面仍然是锁定状态,同一个浏览器的其他标签页在下次切换页面时也会被锁定;
- 输错密码的次数和"已经登录后再输入当前密码"共用一个计数,输错太多次会让所有登录失效,见登录失败锁定。
在线用户与强制下线
在 系统监控 → 在线用户 中可以看到当前所有有效的会话:
- 默认列出用户名、部门、IP 地址、登录地点、客户端(电脑、手机,或者第三方应用的客户端标识)、登录时间、最近访问;浏览器、操作系统、过期时间、是否保持登录和 User-Agent 默认隐藏,可以在列设置里打开。可以按用户名、IP 地址和客户端筛选;
- 用户授权给第三方应用的会话也列在这里,同样可以强退,见监控与日志 · 第三方应用的会话;
- 强退:结束一个会话;强退该用户:结束这个用户在所有设备上的会话,包括第三方应用的;勾选多行后可以批量强退;
- 被强退的一方会立即掉线(通过实时推送),看到"你已被管理员强制下线,请重新登录"并回到登录页。手机端也一样;手机端没连上实时推送时(比如小程序没有配置 socket 合法域名),下次操作时回到登录页。登录日志记一条"被强制退出",写明是哪位管理员操作的;
- 自己当前的会话标着"当前会话",不能勾选也不能强退(要退出请用"退出登录");自己的其他会话可以单独强退,但不能用"强退该用户";
- 非超级管理员只能看到和强退自己数据范围内用户的会话,也不能强退超级管理员。
"登录地点"需要先下载 IP 数据文件,见快速开始。
权限:iam.session.browse(浏览)、iam.session.kick(强退)。
个人中心
点右上角的用户菜单,可以进入个人中心,也可以锁定屏幕、修改密码和退出登录。个人中心左侧显示头像(可以更换)、显示名和用户名,还有只读的部门、角色和岗位;右侧有几个标签页。
基本资料与头像
- 可以修改显示名、手机号、邮箱和性别;用户名不能修改;
- 点更换头像选择图片(png、jpeg、gif、webp),在浏览器里裁剪后上传,保存为 256×256 的图片。
更换手机号
在"基本资料"里修改手机号时,需要:
- 填写当前密码;
- 点获取验证码,验证码发到新号码上,填写收到的短信验证码。
保存后,你在其他设备上的登录都会失效(当前这台保留),旧号码上没用过的验证码也会作废。补充几点:
- 新号码已经属于别的账号时,收不到验证码;
- 每个用户每天最多获取 5 次这种验证码(参数
sms.otp.user_daily_max); - 系统还没有配置短信时,不能在这里修改手机号,需要请管理员在用户管理中修改;
- 清空手机号只需要当前密码。
修改密码
填写旧密码、新密码和确认新密码,新密码不符合密码策略时会直接提示(从用户菜单的"修改密码"进入的独立页面,会在标题下方写明当前的密码策略)。修改后:
- 你在其他设备和浏览器上的登录立即失效,当前这台保留;
- 微信小程序的绑定会解除,需要在小程序里重新绑定。
账号绑定
开启了微信小程序登录,或者账号已经绑定过微信时,才显示这个标签页。这里显示是否已绑定微信小程序和绑定时间,可以解绑:
- 解绑后,这个微信不能再直接登录你的账号,需要重新绑定;
- 解绑会让你在其他手机上的登录全部失效,当前这台保留;
- 关闭了微信登录开关后,仍然可以在这里查看和解绑。
绑定不在这里操作,而是在小程序里完成,见下一节。
偏好设置
选择界面语言,切换后立即生效,系统发给你的通知和导出的文件也使用这种语言,见国际化。
微信小程序登录
员工可以在微信小程序里直接用微信登录。第一次使用时,要把微信和自己的员工账号绑定起来。这个功能默认关闭。
使用过程:
- 打开小程序时,先在后台自动用微信登录,不需要用户操作;
- 这个微信已经绑定了账号时,直接进入工作台;
- 还没有绑定时,进入绑定页,用账号密码或短信验证码登录一次,就完成了绑定。
一个微信只能绑定一个账号,一个账号也只能绑定一个微信。已经绑定过时会提示"该微信已绑定其他账号"或"该账号已绑定微信,请先在个人中心解绑"。绑定的账号被停用后,这个微信也不能登录了。
小程序里的登录总是"保持登录",在线用户里的客户端显示为"手机"。
启用步骤
- 在
apps/server/.env.local中写好WX_MP_APPID和WX_MP_SECRET(小程序的 AppID 和 AppSecret),见环境变量。密钥只能写在这里,不能放进任何会提交到仓库的文件; - 在 系统管理 → 参数设置 中把
auth.wx_mp.enabled改为true; - 在微信公众平台的"开发管理 → 开发设置 → 服务器域名"中,把后端接口的域名加入 request 合法域名;
mobile/src/manifest.json中小程序的appid也填同一个 AppID。
前两步少了任何一项,微信登录和绑定都不可用。
什么时候会自动解绑
本人修改密码、用短信找回密码、管理员重置密码时,这个账号的微信绑定会自动解除。被强制下线或更换手机号不会解绑。
安全方面的规则(一次性凭证、绑定票据等)见安全基线 · 微信小程序登录。
登录日志
系统管理 → 日志管理 → 登录日志 记录每一次登录尝试和会话事件,包括失败的。每条记录有类型、登录名、客户端、IP 地址、登录地点、浏览器、操作系统、是否成功和提示(失败的真实原因,比如"用户名不存在""密码错误""IP 在登录黑名单中")。
| 类型 | 值 | 什么时候记录 |
|---|---|---|
| 密码登录 | password | 账号密码登录,成功或失败 |
| 短信登录 | sms | 短信验证码登录,成功或失败 |
| 微信登录 | wx-mp | 微信小程序登录和绑定,成功或失败 |
| 退出登录 | signout | 用户主动退出 |
| 被强制退出 | kicked | 被管理员强退,提示里写明操作人 |
| 刷新令牌重放 | refresh_reuse | 已经用过的刷新令牌又被使用(可能被盗用),整个会话立即作废 |
| 锁定 | locked | 登录失败次数过多被锁定;或者已登录后输错当前密码次数过多,所有会话失效 |
页面上的操作:
- 查看详情、导出 Excel、删除和清空;
- 解锁账户:选中一行,解除这一行的用户名在所有 IP 上的登录锁定,并清零跨 IP 的失败计数。
权限:audit.signinLog.browse(浏览)、audit.signinLog.view(查看)、audit.signinLog.export(导出)、audit.signinLog.remove(删除和清空)、audit.signinLog.unlock(解锁账户)。
登录日志默认保留 180 天(参数 audit.retention_days,同时控制其他几种日志),过期后由定时任务删除。
相关参数
都在 系统管理 → 参数设置 中修改,改完立即生效。值不合法或者超出范围时按默认值处理。勾选了"登录前可读"的参数,不登录也能读取,因为登录页和注册页要用到。
| 参数键 | 参数名称 | 默认值 | 登录前可读 |
|---|---|---|---|
captcha.mode | 验证码模式(off 关闭 / image 图形 / slider 滑块) | slider | 是 |
captcha.image_type | 图形验证码题型(math 算术 / chars 字符) | math | |
auth.lock_threshold | 登录失败锁定次数 | 5 | |
auth.lock_minutes | 登录锁定时长(分钟) | 10 | |
auth.cross_ip_threshold | 跨 IP 登录失败阈值(每小时) | 10 | |
auth.ip_blacklist | 登录 IP 黑名单 | 空 | |
auth.signup.enabled | 开放注册 | false | 是 |
auth.signup.default_role_id | 注册默认角色 ID | "注册成员"角色的 ID | |
auth.signup.default_dept_id | 注册默认部门 ID | 空 | |
auth.wx_mp.enabled | 微信小程序登录 | false | 是 |
iam.password_min_length | 密码最小长度 | 8 | 是 |
iam.password_char_classes | 密码最少字符类别数 | 2 | 是 |
iam.password_expire_days | 密码有效天数(0 为不过期) | 0 | |
sms.otp.cooldown_sec | 发送冷却时间(秒) | 60 | |
sms.otp.mobile_daily_max | 单手机号每日发送上限 | 10 | |
sms.otp.ip_daily_max | 单 IP 每日发送上限 | 20 | |
sms.otp.user_daily_max | 单用户每日绑定验证码上限 | 5 | |
sms.otp.global_daily_max | 全站每日发送上限 | 1000 | |
audit.retention_days | 日志与记录保留天数(操作/登录/API/任务日志、消息记录、短信验证码、已删除文件) | 180 |
和登录有关的环境变量(改了要重启):ACCESS_TTL_SEC、REFRESH_TTL_SEC、WX_MP_APPID、WX_MP_SECRET,以及初始化数据时 admin 使用的 SEED_ADMIN_PASSWORD,见环境变量。
开发指南
- 参数设置:在代码里读取参数、新增自己的参数;
- 防重复提交、限流与锁:登录、发短信这类接口的限流写法;
- 接口请求:前端怎样自动换新令牌、处理"会话已过期";
- 路由与菜单:登录、注册、找回密码等不需要登录的页面,以及路由守卫的流程;
- 消息通知:短信模板和发送;
- 相关功能:安全基线、权限与数据范围、实时推送、国际化。