业务系统权限管理升级说明
概述
权限限制统一由权限中心控制并且办法token和refresh_token;
统一授权中心地址:http://crm.v2.zbing.net/
token
有效期:待商定
token用来校验身份,可以解析出一下内容,其中 platform_uid 对应 业务系统的 dd_user_id及钉钉用户ID;
['userId' => $employee->id,'platform'=>$platform,'platform_uid'=>$platform_uid, 'userName' => $employee->username, 'cacheKey' => $cacheKey]
refresh_token
refresh_token 用来续期 token
如果获取token
业务系统前端登录已改造成跳转授权中心登录页面进行统一登录,登录成功后会返回业务系统。并携带 refresh_token,进入业务系统并且是用refresh_token获取完整token信息
一下是关于登录获取token的大体改造内容:
业务系统前端
文件:src/permission.js
改造内容:判断用户是否登录根据是否能够拿到token数据,如果没有则跳转到登录页面,其中的getToken方法导入文件是
// 文件位置 /home/baozi/yeziworkplace/yezi_front/src/utils/yzAuth.js
import { getToken } from '@/utils/yzAuth'
关键代码:
/**
* 统一处理跳转登录
*/
function redirectToLogin(to) {
const login_url = process.env.VUE_APP_PRIVATE_LOGIN_URL // 环境变量中设置了统一授权中心的跳转地址
const self_domain = window.location.origin
const yz_rdn_url = self_domain + "/#" + to.path
const yz_redirect_url = encodeURIComponent(yz_rdn_url)
const yz_platform_id = process.env.VUE_APP_PLATFORM_ID || '1' //环境变量中获取VUE_APP_PLATFORM_ID值。默认是1 是必填项
window.location.href = login_url + '?yzplatform=' + yz_platform_id + '&yz_redirect=' + yz_redirect_url
NProgress.done()
}
登录成功后跳回业务系统后的处理关键代码,跳转后会携带authToken参数,其实就是refresh_token
// -------------------------------
// ① 情况一:URL 带 authToken(钉钉登录 / 单点登录)
// -------------------------------
if (to.params.authToken || to.query.authToken) {
const authToken = to.params.authToken || to.query.authToken
// 存入 Vuex & localStorage
store.commit('yzAuth/SET_REFRESH_TOKEN', authToken)
// 使用 authToken 从后台换 refreshToken + 有效期
try {
const newTokenData = await store.dispatch('yzAuth/refreshToken')
if (!newTokenData) {
console.error('authToken 无效,跳转登录')
return redirectToLogin(to)
}
} catch (e) {
console.error('authToken 刷新失败:', e)
return redirectToLogin(to)
}
await store.dispatch('menus/initMenus')
// 清理 URL 中的 authToken,不留脏参数
return next({
path: to.path,
query: Object.assign({}, to.query, { authToken: undefined }),
replace: true
})
}
后台
环境变量新增
# Jwt 密钥
JWT_AUTH_NAME=Authorization
JWT_ACCESS_TOKEN_KEY = {找bao获取}
JWT_REFRESH_TOKEN_KEY = {找bao获取}
JWT_ACCESS_EXPIRE = 1
JWT_REFRESH_EXPIRE = 72
# 权限校验的AppId
AUTH_APP_ID=1b62fff912a632c700e7771b9925722a
AUTH_PLATFORM_ID = 1
1.关于身份的识别
安装了 composer require firebase/php-jwt库 ,新增了 app/Services/JwtService.php文件来解密前端传递的token数据
改造了 app\http\Controller\Controller.php 中的 getUser方法,原来是直接根据传递的dd_userid获取用户信息,再造后是根据token解析出来的dd_userid
$auth_token = $xtoken ?? \Illuminate\Support\Facades\Request::header('x-token');
if (! $auth_token) {
throw new \Error("请重新登录!1001",BaseConstant::NO_LOGIN);
}
try {
$jwtService = new \App\Services\JwtService();
$tokenData = $jwtService->verifyAccessToken($auth_token);
if (! $tokenData) {
throw new \Error("身份认证错误!1002",BaseConstant::NO_LOGIN);
}
} catch (\Exception $e) {
throw new \Error("获取用户数据失败!1003",BaseConstant::NO_LOGIN);
}
$x_token = $tokenData['data']->platform_uid;
2.关于权限节点的拦截
添加全局的中间件拦截器 app/Http/Middleware/YzAuthMiddleware.php,在Kernel.php进行注册。【后期还可考虑不全局放在router配置中】
namespace App\Http\Middleware;
use Closure;
use App\Http\BaseConstant;
use App\Services\YzAuthService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;
use \Illuminate\Support\Facades\Log;
class YzAuthMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
// 获取用户访问的资源路径
$resource = $request->path();
// 获取用户访问方式,是get还是post
$method = strtolower($request->method());
$whiteList = config('white_list');
// 判断是否在白名单中
foreach ($whiteList as $item) {
if (strtolower($item[0]) == $method && $item[1] == $resource) {
return $next($request);
}
}
// 不在白名单,进行权限验证
$auth_token = $xtoken ?? \Illuminate\Support\Facades\Request::header('x-token');
if (! $auth_token) {
return $next($request);
}
$jwtService = new \App\Services\JwtService();
$tokenData = $jwtService->verifyAccessToken($auth_token);
if ($tokenData && isset($tokenData['data']) && $tokenData['data']->userId>0) {
$permissionsData = Redis::get('permissions:' . $tokenData['data']->platform_uid);
if(!$permissionsData){
// 根据 tokenData 设置用户信息,并且获取用户所有的权限数据
$yzAuthService = new YzAuthService();
$user = $yzAuthService->getUserPermissions($tokenData['data']->userId);
Redis::set('permissions:' . $tokenData['data']->platform_uid, json_encode($user),'EX', 3600);
}else{
$permissionsData = json_decode($permissionsData, true);
}
foreach ($permissionsData['api'] as $perm) {
if (isset($perm['path']) && isset($perm['method'])) {
if ($perm['path'] == $resource && strtolower($perm['method']) == $method) {
// 用户有权限访问该资源
return $next($request);
}
}
}
return response()->json(['code' => BaseConstant::RETURN_FAIL_NORMAL, 'message' =>'暂无该资源权限访问该资源!']);
}
return $next($request);
}
}
同时支持白名单配置 config/white_list.php ,在白名单中的不进行权限拦截和校验。
<?php return [ // 白名单列表 ['get','api/refresh_token'], // ['get','api/dingtalk/get_user_info'] ];
3.关于人员查看数据范围的控制改造
在文件 app/Services/YzAuthService.php 中有一下两个函数来生成查询sql的 whereIn(dd_dept_id,$dd_dept_list) 赋值
/**
* 获取用户的数据操作范围
* @param \Illuminate\Database\Eloquent\Builder $query 当前的查询构建器
* @param string $field_name 用户ID字段名
* @param string $dept_field_name 部门ID字段名
* @param string $type 操作类型('read' 或 'write')
* @param string $alias 查询表别名
* @param \Closure|null $callback 自定义查询逻辑闭包
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getUserScopeSql(&$query, $field_name = 'dd_user_id', $dept_field_name = 'dd_dept_id', $type = 'read', $alias = '')
{
// 获取auth_token
$auth_token = $xtoken ?? \Illuminate\Support\Facades\Request::header('x-token');
if (!$auth_token) {
throw new \Error($responseBody['message'] ?? '构造用户数据操作范围失败');
}
// 验证token
$jwtService = new \App\Services\JwtService();
$tokenData = $jwtService->verifyAccessToken($auth_token);
// 从Redis获取权限数据
$permissionsData = Redis::get('permissions:' . $tokenData['data']->platform_uid);
if (!$permissionsData) {
throw new \Error($responseBody['message'] ?? '构造用户数据操作范围失败222');
}
$permissionsData = json_decode($permissionsData, true);
// 默认的权限查询逻辑
$data_scope = $permissionsData['scope_type'] ?? '1';
if ($data_scope === '1') {
$query->where(($alias ? $alias . '.' : '') . $field_name, $tokenData['data']->platform_uid);
} elseif (in_array($data_scope, [2, 3, 4])) {
$query->where(function ($_q) use ($field_name, $dept_field_name, $alias, $permissionsData, $tokenData, $type) {
if ($type === 'read') {
$_q->whereIn(($alias ? $alias . '.' : '') . $dept_field_name, $permissionsData['platforms_read_scope'] ?? [])
->orWhere(($alias ? $alias . '.' : '') . $field_name, $tokenData['data']->platform_uid);
} else {
$_q->whereIn(($alias ? $alias . '.' : '') . $dept_field_name, $permissionsData['platforms_write_scope'] ?? [])
->orWhere(($alias ? $alias . '.' : '') . $field_name, $tokenData['data']->platform_uid);
}
});
}
return $query;
}
/**
* 获取用户的数据操作范围
* @param \Illuminate\Database\Eloquent\Builder $query 当前的查询构建器
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getUserScopeSqlByFunc(&$query,$callback)
{
// 获取auth_token
$auth_token = $xtoken ?? \Illuminate\Support\Facades\Request::header('x-token');
if (!$auth_token) {
throw new \Error($responseBody['message'] ?? '构造用户数据操作范围失败');
}
// 验证token
$jwtService = new \App\Services\JwtService();
$tokenData = $jwtService->verifyAccessToken($auth_token);
// 从Redis获取权限数据
$permissionsData = Redis::get('permissions:' . $tokenData['data']->platform_uid);
if (!$permissionsData) {
throw new \Error($responseBody['message'] ?? '构造用户数据操作范围失败222');
}
$permissionsData = json_decode($permissionsData, true);
// 执行用户自定义查询逻辑
return $callback($query, $permissionsData, $tokenData);
}
使用方法说明
情况一,逻辑简单
以CustomerController.php获取意向客户列表举例
原来代码使用if-else 判断role角色获取对应的人员拥有的dept_list数据,改版后通过 权限系统直接获取人员被赋值的dept_list
原代码
$dept_list = [];
if (! CommonController::ifPermissions($user['roles'], 'customer') && ! ($user['admin'] && $user['admin'] == true)) {
return response()->json(['code'=>BaseConstant::NO_PERMISSIONS, 'message'=>'无权限']);
} else {
if (in_array($user['userid'], config('dingtalk.customer_admin'))) {
$dept_list = CompanySignInfo::query()->pluck('dd_dept_id')->toArray();
$listQuery->where(function($query) use($dept_list, $user) {
$query->whereIn('crm_customer.dd_dept_id', $dept_list)->orWhere('crm_customer.dd_user_id', $user['userid']);
});
} elseif (in_array('admin', $user['roles'])) {
$dept_list = User::getUserManageDepartmentList($user['userid']);#var_dump($dept_list);
$listQuery->where(function($query) use($dept_list, $user) {
$query->whereIn('crm_customer.dd_dept_id', $dept_list)->orWhere('crm_customer.dd_user_id', $user['userid']);
});
} elseif ($user['roles'] == ['user'] || in_array('fts', $user['roles']) || in_array('auditor', $user['roles'])) {
$dept_list = UserCompany::getUserCompanys($user['userid']);
if (isset($queryParam['status']) && $queryParam['status'] == BaseConstant::CUSTOMER_STATUS['PUBLIC']) {
if (count($dept_list)) {
$listQuery->whereIn('crm_customer.dd_dept_id', $dept_list);//todo 获取用户是哪个分公司的
} else {
throw new \Error("用户没有设置部门,请联系管理员");
}
} else {
$listQuery->where('crm_customer.dd_user_id', $user['userid']);
}
} elseif (in_array('accounting_manager', $user['roles'])) {
$dept_list = User::getUserManageDepartmentList($user['userid']);#var_dump($dept_list);
// var_dump($dept_list);
$listQuery->where(function($query) use($dept_list, $user) {
$query->whereIn('crm_customer.dd_dept_id', $dept_list)->orWhere('crm_customer.dd_user_id', $user['userid']);
});
// } elseif (in_array('outwork_manager', $user['roles']) && ! in_array('manager', $user['roles'])) {
} elseif (in_array('area_manager', $user['roles'])) {
$dept_list = User::getUserManageDepartmentList($user['userid']);#var_dump($dept_list);
$listQuery->where(function($query) use($dept_list, $user) {
$query->whereIn('crm_customer.dd_dept_id', $dept_list)->orWhere('crm_customer.dd_user_id', $user['userid']);
});
} elseif (in_array('manager', $user['roles'])) {
if (in_array($user['userid'], ['1670909952913521', '16926732771311962'])) {
$dept_list = UserCompany::getUserCompanys('16484309558114235');
} else {
$dept_list = User::getUserManageDepartmentList($user['userid']);#var_dump($dept_list);
}
$listQuery->where(function($query) use($dept_list, $user) {
$query->whereIn('crm_customer.dd_dept_id', $dept_list)
->orWhere('crm_customer.dd_user_id', $user['userid']);
});
} elseif (in_array('area_personnel', $user['roles'])) {
$dept_list = User::getUserManageDepartmentList($user['userid']);#var_dump($dept_list);
$listQuery->where(function($query) use($dept_list, $user) {
$query->whereIn('crm_customer.dd_dept_id', $dept_list)->orWhere('crm_customer.dd_user_id', $user['userid']);
});
} elseif (in_array('reserve_manager', $user['roles'])) {
$dept_list = User::getUserManageDepartmentList($user['userid']);#var_dump($dept_list);
$listQuery->where(function($query) use($dept_list, $user) {
$query->whereIn('crm_customer.dd_dept_id', $dept_list)->orWhere('crm_customer.dd_user_id', $user['userid']);
});
} elseif(in_array($user['userid'], ['1655709808481485', '1653355988159449', '034239376726249358'])) {//侯俊萌/申振华/李旦旦 需要看销售意向,莘县王燕不需要看销售意向
$dept_list = User::getUserManageDepartmentList($user['userid']);#var_dump($dept_list);
$listQuery->where(function($query) use($dept_list, $user) {
$query->whereIn('crm_customer.dd_dept_id', $dept_list)->orWhere('crm_customer.dd_user_id', $user['userid']);
});
} elseif (in_array('outwork_manager', $user['roles'])) {
if (isset($queryParam['status']) && $queryParam['status'] == BaseConstant::CUSTOMER_STATUS['PUBLIC']) {
$dept_list = User::getUserManageDepartmentList($user['userid']);
if (count($dept_list)) {
$listQuery->whereIn('crm_customer.dd_dept_id', $dept_list);//todo 获取用户是哪个分公司的
} else {
throw new \Error("用户没有设置部门,请联系管理员");
}
} else {
$dept_list = User::getUserManageDepartmentList($user['userid']);
$kj_users = User::query()
->leftJoin('crm_user_company_relation', 'crm_users.userid', '=', 'crm_user_company_relation.dd_user_id')
->whereIn('crm_user_company_relation.dd_dept_id', $dept_list)
->whereIn('crm_users.position_title', config('dingtalk.accounting_position'))
->pluck('crm_users.userid')->toArray();
$kj_users[] = $user['userid'];
$listQuery->whereIn('dd_user_id', $kj_users);
}
} elseif (in_array('m0_manager', $user['roles'])) {
if (isset($queryParam['status']) && $queryParam['status'] == BaseConstant::CUSTOMER_STATUS['PUBLIC']) {
$dept_list = UserCompany::getUserCompanys($user['userid']);
if (count($dept_list)) {
$listQuery->whereIn('crm_customer.dd_dept_id', $dept_list);//todo 获取用户是哪个分公司的
} else {
throw new \Error("用户没有设置部门,请联系管理员");
}
} else {
$dept_list = UserCompany::getUserCompanys($user['userid']);
$sale_users = User::query()
->leftJoin('crm_user_company_relation', 'crm_users.userid', '=', 'crm_user_company_relation.dd_user_id')
->whereIn('crm_user_company_relation.dd_dept_id', $dept_list)
->whereIn('crm_users.position_title', config('dingtalk.sale_position'))
->pluck('crm_users.userid')->toArray();
$sale_users[] = $user['userid'];
$listQuery->whereIn('dd_user_id', $sale_users);
}
} elseif (in_array('gc_outwork_manager', $user['roles'])) {
$dept_list = UserCompany::getUserCompanys($user['userid']);
if (isset($queryParam['status']) && $queryParam['status'] == BaseConstant::CUSTOMER_STATUS['PUBLIC']) {
if (count($dept_list)) {
$listQuery->whereIn('crm_customer.dd_dept_id', $dept_list);//todo 获取用户是哪个分公司的
} else {
throw new \Error("用户没有设置部门,请联系管理员");
}
} else {
$listQuery->where('crm_customer.dd_user_id', $user['userid']);
}
} else {
$listQuery->where('crm_customer.dd_user_id', $user['userid']);
}
}
升级后代码
$yzAuthService = new \App\Services\YzAuthService();
$listQuery = $yzAuthService->getUserScopeSql($listQuery,'crm_customer.dd_user_id','crm_customer.dd_dept_id','read');
将升级后代码替换以上就代码即可,新代码getUserScopeSql方法返回一个 $listQuery->whereIn(‘crm_customer.dd_dept_id’, $dept_list);或者 $listQuery->where(‘crm_customer.dd_user_id’, $user[‘userid’])对象其中$dept_list根据权限系统中赋值
情况二,以线索列表举例
原代码
if (!CommonController::ifPermissions($user['roles'], 'customer') && !($user['admin'] && $user['admin'] == true)) {
return response()->json(['code' => BaseConstant::NO_PERMISSIONS, 'message' => '无权限']);
} else {
if ($user['roles'] == ['user']) {
// $user_company_dept_id = Department::getDepartmentCompany($user['dept_id_list'][0]);
// $dept_list = [$user_company_dept_id];
$dept_list = UserCompany::getUserCompanys($user['userid']);
if (isset($queryParam['status']) && $queryParam['status'] == BaseConstant::CUSTOMER_STATUS['PUBLIC']) {
if (count($user['dept_id_list'])) {
$listQuery->whereIn('crm_lead.dd_dept_id', $dept_list);
} else {
throw new \Error("用户没有设置部门,请联系管理员");
}
} else {
$listQuery->where('crm_lead.dd_user_id', $user['userid']);
}
} else {
$dept_list = User::getUserManageDepartmentList($user['userid']);
$listQuery->where(function ($query) use ($dept_list, $user) {
$query->whereIn('crm_lead.dd_dept_id', $dept_list);
});
}
}
升级后代码
$yzAuthService = new \App\Services\YzAuthService();
$listQuery = $yzAuthService->getUserScopeSqlByFunc(
$listQuery,
function($query, $permissionsData, $tokenData)use($queryParam) {
// 1.仅看自己 2.本部门 3.本部门及以下部门,4 指定部门 5.所有部门
$data_scope = $permissionsData['scope_type'] ?? '1';
if($data_scope === '1'){
if (isset($queryParam['status']) && $queryParam['status'] == BaseConstant::CUSTOMER_STATUS['PUBLIC']) {
$query->whereIn('crm_lead.dd_dept_id', $permissionsData['platforms_read_scope']);
}else {
$query->where('crm_lead.dd_user_id', $tokenData['data']->platform_uid);
}
}elseif(in_array($data_scope, [2,3,4])) {
$query->where(function($_q) use( $permissionsData,$tokenData) {
$_q->whereIn('crm_lead.dd_dept_id', $permissionsData['platforms_read_scope'] ?? [])
->orWhere('crm_lead.dd_user_id',$tokenData['data']->platform_uid);
});
在回调函数中 会携带两个参数 $permissionsData 用户权限数据明细, $tokenData可以根据 $tokenData[‘data’]->platform_uid获取当前用户dd_userid
权限明细$permissionsData存储在redis中,数据结构如下
其中 user_id,user_name,roles 是权限系统的id和角色,目前可以忽略。
api 对应后台的路由节点权限
pages 对应前端的菜单和页面权限
btn 对应前端页面的按钮级别权限
**** 比较重要的有 scope_type 和 platforms_read_scope”,platforms_write_scope
其中scope_type值 1.仅看自己 2.本部门 3.本部门及以下部门,4 指定部门 5.所有部门,当为5是表示不限制,返回的platforms_read_scope和platforms_write_scope是空。
platforms_read_scope 是用户有读权限的 dd_dept_list
platforms_write_scope 是用户有写权限的 dd_dept_list
{
"user_id": 45,
"user_name": "张冰",
"roles": [
{
"role_id": 1,
"role_name": "超级管理员"
}
],
"api": [
{
"title": "公共方法",
"method": "GET",
"path": "api/dingtalk/get_user_info",
"tag_name": "公共方法"
},
{
"title": "获取消息列表",
"method": "GET",
"path": "api/dingtalk/get_notices_list",
"tag_name": "公共方法"
},
{
"title": "获取部门列表树",
"method": "GET",
"path": "api/dingtalk/task/get_dept_tree",
"tag_name": "公共方法"
},
{
"title": "获取新面板数据",
"method": "POST",
"path": "api/dingtalk/newdashboard",
"tag_name": "公共方法"
},
{
"title": "获取未完成任务列表",
"method": "GET",
"path": "api/dingtalk/task/un_done_count",
"tag_name": "公共方法"
},
{
"title": "获取新面板销售过程两数据",
"method": "GET",
"path": "api/dingtalk/dashboard/get_sale_info_day",
"tag_name": "公共方法"
},
{
"title": "recruit_amount_add_day",
"method": "GET",
"path": "api/dingtalk/recruit/recruit_amount_add_day",
"tag_name": "公共方法"
},
{
"title": "获取合同部门列表",
"method": "GET",
"path": "api/dingtalk/department/get_contract_department_list",
"tag_name": "公共方法"
},
{
"title": "客户列表",
"method": "GET",
"path": "api/dingtalk/customer/list",
"tag_name": "客户管理"
},
{
"title": "电话本列表",
"method": "GET",
"path": "api/dingtalk/customer_lead/list",
"tag_name": "客户管理"
},
{
"title": "个人简介",
"method": "GET",
"path": "api/dingtalk/user/get_user_profile",
"tag_name": "公共方法"
},
{
"title": "企业库查询条件",
"method": "GET",
"path": "api/dingtalk/enterprise_info_db/base_info",
"tag_name": "客户管理"
},
{
"title": "找资源列表",
"method": "GET",
"path": "api/dingtalk/enterprise_info_db/enterprise_info_list",
"tag_name": "客户管理"
},
{
"title": "获取人员目标数据",
"method": "GET",
"path": "api/dingtalk/usertarget/get_company_user_target_list",
"tag_name": "公共方法"
},
{
"title": "长时间未跟进客户",
"method": "GET",
"path": "api/dingtalk/get_follow_cold",
"tag_name": "新工作台"
},
{
"title": "获取城市管理人日报配置",
"method": "GET",
"path": "api/dingtalk/magager_ribao/getBaseManagerRibaoConfig",
"tag_name": "新工作台"
}
],
"pages": [
{
"id": 2,
"title": "客户",
"en_title": "view",
"locale": "menus.view",
"parent_id": 24,
"name": "menu_customer",
"method": "POST",
"path": "/customer",
"icon": null,
"type": 1,
"sort_order": 100,
"tag_name": "意向客户管理"
},
{
"id": 3,
"title": "意向客户",
"en_title": "22",
"locale": "23",
"parent_id": 2,
"name": "menu_customer_list",
"method": "GET",
"path": "/customer/customer_list",
"icon": "23",
"type": 1,
"sort_order": 100,
"tag_name": "23"
},
{
"id": 4,
"title": "电话本",
"en_title": "22",
"locale": "323",
"parent_id": 2,
"name": "menu_customer_lead",
"method": "GET",
"path": "/customer/customer_lead",
"icon": null,
"type": 1,
"sort_order": 100,
"tag_name": "ass"
},
{
"id": 5,
"title": "找资源",
"en_title": "222",
"locale": "222",
"parent_id": 2,
"name": "menu_enterprise_info",
"method": "GET",
"path": "/customer/enterprise_info",
"icon": null,
"type": 1,
"sort_order": 100,
"tag_name": "ass"
}
],
"btn": [
{
"title": "【btn】新增意向客户按钮",
"name": "yzbtn_customer_add",
"method": "GET",
"path": "yzbtn_customer_add",
"icon": null,
"sort_order": 100,
"tag_name": null
}
],
"scope_type": 5,
"scope_type_name": "所有部门",
"read_scope": [],
"write_scope": [],
"platforms_read_scope": [],
"platforms_write_scope": [],
"status": 1
}
前台
1.新增了环境变量
# 统一授权登录地址 可以设置成 http://crm.v2.zbing.net/ 线上地址方便开发
VUE_APP_PRIVATE_LOGIN_URL = http://localhost:8000/user/login
# 平台类型ID
VUE_APP_PLATFORM_ID = 1
# 是否后台权限控制菜单显示
VUE_APP_SHOW_MENU_BY_AUTH = 0
2.修改 main.js
再大约53行添加了代码,注册v-yzauth指令,用于控制页面中按钮级别的权限控制,
import yzauth from '@/directive/yzauth'
Vue.use(yzauth)
使用示例:
其中 v-yzauth后面的 yzbtn_customer_add 对应权限系统的中添加的按钮节点path值
<el-button style="margin-left: 10px" v-yzauth="'yzbtn_customer_add'" type="success" @click="handleCreate">
新增客户
</el-button>

3. 前端存储token的代码 src/store/modules/yzAuth.js
4. 前端刷新token的关键代码
文件:src/utils/request.js
service.interceptors.request.use(
async config => {
// 1. 请求时,检查 token 是否需要刷新
const newToken = await store.dispatch("yzAuth/ensureValidAccessToken")
// 2. 获取当前有效 token
const finalToken = newToken || getToken()
if (finalToken) {
config.headers['X-Token'] = finalToken
}
return config
},
error => {
console.error("Request error:", error)
return Promise.reject(error)
}
)
5.关于业务前端菜单根据权限控制显示的代码
文件:src/store/modules/permission.js
// 根据后台权限数据过滤路由
function filterRoutesByAuth(routes, parentPath = '') {
const result = []
routes.forEach(route => {
const tmp = { ...route }
// 构造当前路由的完整路径
const fullPath = parentPath + (tmp.path.startsWith('/') ? tmp.path : '/' + tmp.path)
const menusData = store.state.menus.menusData
// 判断当前路由是否在权限数据中
if(menusData && menusData.length > 0){
const menu = menusData.find(item => item.path == fullPath)
// 判断menu 是否 是undefined,如果是,则不显示
if(menu){
// 如果有子路由,递归处理
if (tmp.children) {
tmp.children = filterRoutesByAuth(tmp.children, fullPath)
}
result.push(tmp)
}
}
})
return result
}
const actions = {
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
let accessedRoutes
if (roles.includes('admin')) {
accessedRoutes = asyncRoutes || []
} else {
// 这里根据环境变量判断是否开启权限控制菜单的显示
if(process.env.VUE_APP_SHOW_MENU_BY_AUTH == '1'){
accessedRoutes = filterRoutesByAuth(asyncRoutes,'');
}else{
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles);
}
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
控制的部分延用了原来的逻辑,只控制了 /src/router/index.js中的 export const asyncRoutes 部分。
6.按钮控制使用 前面2中说的v-yzauth指令
<el-button style="margin-left: 10px" v-yzauth="'yzbtn_customer_add'" type="success" @click="handleCreate">
新增客户
</el-button>