Note 01 of 06: 笔记 01 / 06:Local Account Permission Rules本地账户的权限判断

Separating actor, target and action in Seamly2D role management, then checking state changes and persistence.从 Seamly2D 的本地角色管理出发,拆开操作者、目标账户与操作,再检查状态变化和保存结果。

Building local accounts for Seamly2D, the part that actually made me think was one rule in role management. An administrator can promote a normal user to administrator, but an existing administrator can be demoted only by the admin account. For the very same target account, a change of role can turn an allowed operation into a forbidden one. A single administrator label on the current user cannot express all of that.

给 Seamly2D 做本地账户,真正让人动脑子的是角色管理里的一条规则:管理员可以把普通用户升成管理员,可已有的管理员,只有 admin 这个账号能给他降级。同一个目标账户,角色一变,原来允许的操作就可能不再允许。光给当前用户贴一个管理员标签,这件事是说不完的。

Account Operation Permissions账户操作权限

Deciding whether an account operation may proceed starts with the actor, then looks at the target account and the requested action, and the table follows that order. Here admin means the original special account, and an ordinary administrator is any other account later given the Admin role.

判断一项账户操作能不能做,先定操作者,再看目标账户和请求的动作,下表就按这个顺序排。admin 指最初那个特定账户,普通管理员指后来拿到 Admin 角色的其他账户。

ActorTargetActionDecision
Normal userOther accountsManagement operationReject
Ordinary administratorNormal userPromote to administratorAllow
Ordinary administratorNormal userDeleteAllow after confirmation
Ordinary administratorExisting administratorDelete or demoteReject
adminAnother administratorDemoteAllow
操作者目标操作判断
普通用户其他账户管理操作拒绝
普通管理员普通用户升级为管理员允许
普通管理员普通用户删除确认后允许
普通管理员已有管理员删除或降级拒绝
admin其他管理员降级允许

Laid out like this, the table makes plain that role is just one condition among several. It also matters whether the actor is acting on themselves, whether the target still exists, and what state the operation leaves behind. OWASP's authorization guidance likewise frames permission as a relationship between subject, resource and action. Login settles who you are; every concrete operation still has to ask whether you may.

表一摊开,角色只是条件之一就很明显了。还得知道操作者是不是在动自己、目标还在不在、操作之后剩下什么状态。OWASP 的授权说明也是把权限放在主体、资源和动作的关系里讨论的。登录只解决了你是谁,每做一项具体操作,还得再问一次能不能做。

Username Rules and Account Initialization用户名规则与账户初始化

In the project's public role-query excerpt, roleOf() first compares the username with admin, ignoring case, and returns Admin on a match; for everyone else it reads the stored role from QSettings. That function can say what role an account has, but it cannot hold the whole operation table. Two accounts with exactly the same Admin enum value can still have different demotion rights.

项目的公开角色查询节选里,roleOf() 先忽略大小写比较用户名是不是 admin,是就直接返回 Admin;其他用户再从 QSettings 里读保存的角色。这个函数回答得了账户是什么角色,却装不下整张操作表。两个账户的 Admin 枚举值一模一样,降级权限照样可以不同。

Role queries and operation checks are therefore best kept apart. The first only reads account attributes; the second takes an authenticated actor, a freshly read target account and an action, and then decides. Username normalization needs one consistent definition as well. Treat Admin and admin as two names when creating accounts and as the same special identity when looking up roles, and the rules end up contradicting each other.

所以角色查询和操作判断最好分开。前者只管读账户属性;后者拿到已确认身份的操作者、刚读出来的目标账户和动作,再下判断。用户名的规范化也得统一口径。创建账户时把 Admin 和 admin 当成两个名字,查角色时又把它们当成同一个特殊身份,规则自己就打架了。

The special account also raises a question about the starting state. The project required the first user in an empty account store to be created as admin; once accounts exist, registration follows the normal path. Initialization, registration and management all need to recognize accounts by the same rules instead of each interpreting usernames its own way.

这个特殊账户还牵出一个初始状态的问题。按项目要求,空账户库里的第一个用户要建成 admin;有了账户以后,注册就走普通流程。初始化、注册和管理操作得用同一套规则认账户,不能各解释各的用户名。

Permission Checks Before Execution执行前的权限检查

Hiding the management entry from normal users makes the interface much cleaner. When an account is actually changed, though, the executing function should still check permission itself. Menus, shortcuts and other windows may all become new callers later, and a check that lives only in whether a button is visible is easy to miss when another entry point is added.

普通用户看不到管理入口,界面清爽很多。可真正改账户的时候,执行函数最好自己再判断一遍权限。菜单、快捷键、别的窗口,将来都可能变成新的调用入口,判断要是只挂在按钮显不显示上,后面一加入口就容易漏。

A deletion confirmation also hides a gap in time. When the dialog opens, the target is a normal user; by the time the actor clicks confirm, its role may have changed or the account may already be gone. A safer order is to reload the account state immediately before execution, check permission, and then save the change. Cancellation, a vanished target or insufficient permission should all end the operation with account data untouched.

删除确认还夹着一段时间差。对话框弹出来时,目标还是普通用户;等操作者点下确认,它的角色可能变了,账户也可能已经没了。比较稳的顺序是执行前重新读一次账户状态,判断权限,再保存修改。取消、目标消失、权限不够,都直接结束这次操作,账户数据一点不动。

Deleting or demoting an administrator also needs a look at the result. If the product must always keep some management capability, removing the last usable administrator should be refused. That condition concerns the whole set of accounts, and watching only the target's current role will never catch it. Working this out from the present special-admin rule also lays groundwork for replacing the special username with explicit permission attributes later.

管理员的删除和降级,还要单独看操作之后的结果。如果产品要求任何时候都得留着管理能力,那删掉最后一个能用的管理员就该被拒绝。这个条件看的是整组账户,只盯着目标当前的角色是看不出来的。以现在特殊 admin 的规则为起点把这一点想清楚,以后要是把特殊用户名换成明确的权限属性,也算打好了底子。

Saving Account Data with QSettingsQSettings 账户数据保存

QSettings makes saving settings easy, but the save itself has an outcome. Qt's documentation notes that changes may be written later, that sync() synchronizes them, and that status() reports access or format errors. If a role changes on screen and reverts after a restart, the user has experienced a failed operation. Before announcing success, the interface should take the persistence result into account.

QSettings 存设置很省事,但保存这个动作本身也有结果。Qt 文档里写了,修改可能延迟写入,sync() 负责同步,status() 可以查访问或格式错误。界面上角色已经改了,一重启又变回去,对用户来说这就是一次失败的操作。所以提示成功之前,得先把持久化有没有成功也算进去。

These accounts live on the local machine, so the trust model reaches all the way to the operating-system account and the storage location. Restraining someone who can edit the local settings file directly would take more than an in-app role table; the data storage and access control would need a different design. That requirement has to be decided before extending local accounts in that direction.

这些账户存在本机,信任关系也就一路延伸到操作系统账户和存储位置。要是还想管住那些能直接改本地设置文件的人,应用里的一张角色表就不够用了,数据存储和访问控制都得换一种设计。往这个方向扩展本地账户之前,这个需求得先定下来。

The set of exercises I most want to finish is running every allowed and rejected row of the table, then adding cancelled confirmations, vanished targets, restarts after an edit and keeping the last administrator. When role management is complete, any operation can be explained in full: who started it, whom it acted on, and what state it left. The window is just the door through which people use those rules.

最想补的一组练习,是把表里允许和拒绝的情况全跑一遍,再加上取消确认、目标消失、改完重启、保住最后一个管理员这几种情况。角色管理做完整了,一次操作是谁发起的、对谁做的、最后留下什么状态,都能说得清清楚楚。窗口只是让人用上这套规则的那扇门。

06Back to the project回到项目Seamly2D Qt Development Internship南京图灵 Seamly2D 开发实习