上一章自己创建了一个模块,我们注意到前端代码中对于按钮有v-hasPermi=“[‘xxx:testxxx:add’]“这种代码。服务端有@PreAuthorize(”@ss.hasPermi(‘xxx:testxxx:add’)”)这种代码。这是为了分别在前端和服务端限制用户进行非权限操作的。接下来,我们举个例子进行具体分析。
我们来看“新增”按钮对应的前端代码:
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['xxx:testxxx:add']"
>新增</el-button>
这里有一个属性v-hasPermi=“[‘xxx:testxxx:add’]”,这是一个自定义的指令。我们找到该指令定义的位置directive/permission/hasPermi.js。
import store from '@/store'
export default {
inserted(el, binding, vnode) {
const { value } = binding
const all_permission = "*:*:*";
const permissions = store.getters && store.getters.permissions
if (value && value instanceof Array && value.length > 0) {
const permissionFlag = value
const hasPermissions = permissions.some(permission => {
return all_permission === permission || permissionFlag.includes(permission)
})
if (!hasPermissions) {
el.parentNode && el.parentNode.removeChild(el)
}
} else {
throw new Error(`请设置操作权限标签值`)
}
}
}
这里大体的意思就是,从store中获取用户所拥有的所有权限,遍历用户的权限,判断是不是包含"* : * : *"这种所有的权限或者能匹配上v-hasPermi传过来的数组参数中的一个。如果匹配上了,就继续;如果匹配不上,需要把该节点从父节点删除。store中保存的用户的权限是从哪里获取的呢。菜单获取章节,我们学习了菜单获取的过程,返回的菜单结构中就包含了perms字段,里面就是保存的对应菜单的权限。
添加按钮菜单权限的界面。此处就是将数据保存到sys_menu表中。
用户是属于某个角色的,我们看一下角色授权菜单的界面。这里是将数据存到sys_role_menu表。表明角色拥有哪些菜单和按钮的权限。
接下来,我们看一下服务端对权限的控制。TestXxxController.java。
/**
* 新增测试功能
*/
@PreAuthorize("@ss.hasPermi('xxx:testxxx:add')")
@Log(title = "测试功能", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody TestXxx testXxx)
{
return toAjax(testXxxService.insertTestXxx(testXxx));
}
@PreAuthorize 注解,顾名思义是进入方法前的权限验证,@PreAuthorize 声明这个方法所需要的权限表达式。我们来看一下@ss.hasPermi(‘xxx:testxxx:add’)。
@Service("ss")
public class PermissionService
{
/** 所有权限标识 */
private static final String ALL_PERMISSION = "*:*:*";
/** 管理员角色权限标识 */
private static final String SUPER_ADMIN = "admin";
private static final String ROLE_DELIMETER = ",";
private static final String PERMISSION_DELIMETER = ",";
@Autowired
private TokenService tokenService;
/**
* 验证用户是否具备某权限
*
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
public boolean hasPermi(String permission)
{
if (StringUtils.isEmpty(permission))
{
return false;
}
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
{
return false;
}
return hasPermissions(loginUser.getPermissions(), permission);
}
/**
* 验证用户是否不具备某权限,与 hasPermi逻辑相反
*
* @param permission 权限字符串
* @return 用户是否不具备某权限
*/
public boolean lacksPermi(String permission)
{
return hasPermi(permission) != true;
}
/**
* 验证用户是否具有以下任意一个权限
*
* @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表
* @return 用户是否具有以下任意一个权限
*/
public boolean hasAnyPermi(String permissions)
{
if (StringUtils.isEmpty(permissions))
{
return false;
}
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
{
return false;
}
Set<String> authorities = loginUser.getPermissions();
for (String permission : permissions.split(PERMISSION_DELIMETER))
{
if (permission != null && hasPermissions(authorities, permission))
{
return true;
}
}
return false;
}
......
/**
* 判断是否包含权限
*
* @param permissions 权限列表
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
private boolean hasPermissions(Set<String> permissions, String permission)
{
return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
}
}
@ss标签对应的PermissionService,后端的代码和前端的代码很相似。都是先获取用户所拥有的权限,然后对比hasPermi传入的参数。匹配上了,请求处理函数就可被调用;否则,拒绝请求。
上一章,若依前后端分离框架学习-4:创建模块
下一章,若依前后端分离框架学习-6:日志管理
返回目录