多角色 App 中,普通用户不应看到提现按钮、运营才可见导出入口,这类按钮与字段级控制比页面级权限更细。UniApp 没有自定义指令可用,把权限判断收敛成 hasAuth 函数后,模板里一行 v-if 即可完成控制。

实现思路

登录接口返回当前账号的权限码数组(形如 finance/withdraw、order/export),存入本地存储;hasAuth 接收所需权限码并比对返回布尔值。按钮用 v-if 整块移除,敏感字段做掩码展示,后端仍须二次校验。

权限存储与判断

// utils/auth.js
export function setAuthCodes(codes) {
    uni.setStorageSync("authCodes", codes || []);
}

export function hasAuth(code) {
    const codes = uni.getStorageSync("authCodes") || [];
    const list = Array.isArray(code) ? code : [code];
    // some 任一命中即通过,every 则要求全部拥有
    return list.some((item) => codes.includes(item));
}

组合式函数封装

// composables/useAuth.js
import { hasAuth } from "/utils/auth";

export function useAuth() {
    return { hasAuth };
}

模板中的按钮控制

页面引入 hasAuth 后,直接在 template 用 v-if 判断;无权限的按钮整个不渲染,金额类字段可做掩码降级。

<button v-if="hasAuth('finance/withdraw')">提现</button>
<view v-if="hasAuth('finance/seeAmount')">余额:{{ amount }}</view>
<view v-else>余额:***</view>

注意:Vue 模板表达式内建议用 ' 实体表示字符串,避免与属性引号冲突。

登录后的初始化

async function doLogin() {
    const data = await http.post("/auth/login", {...form});
    uni.setStorageSync("token", data.token);
    setAuthCodes(data.authCodes);
    uni.reLaunch({ url: "/pages/index/index" });
}

需要注意

  • 前端控制只影响体验,敏感操作必须由后端校验权限码,防止直接构造请求越权;
  • 权限码沿用 模块/动作 的斜杠风格,与后端权限点一一对应;
  • 退出登录时同步清除 authCodes,避免串号后残留上一账号权限;
  • 权限码变化通常需要重新拉取用户信息,可放在登录后初始化流程统一刷新。

小结

按钮与字段级权限的核心是权限码一致性与后端强校验。前端把判断封装好,页面零成本接入,即可实现细粒度访问控制。