若依源码:自定义权限实现
博客:https://www.emanjusaka.com
博客园:https://www.cnblogs.com/emanjusaka
公众号:emanjusaka的编程栈
RuoYi 的权限框架选择了使用的是 Spring Security。通过使用注解@PreAuthorize("@ss.hasPermi('system:dept:add')")
进行权限控制。
这里的@PreAuthorize
是 Spring Security 提供的权限注解之一,它允许你定义一个 SpEL(Spring Expression Language)表达式,用来在方法执行之前检查用户的权限。
RuoYi 在 PermissionService
类中自定义了 六个权限判断的方法,分别是:
- 验证用户是否具备某权限
- 验证用户是否不具备某权限
- 验证用户是否具有以下任意一个权限
- 判断用户是否拥有某个角色
- 验证用户是否不具备某角色
- 验证用户是否具有以下任意一个角色
具体实现
判断是否包含权限
/**
* 判断是否包含权限
*
* @param permissions 权限列表
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
private boolean hasPermissions(Set<String> permissions, String permission)
{ // 如果权限列表中包含所有权限的标识
return permissions.contains(Constants.ALL_PERMISSION) ||
// 或者权限列表中包含经过去除首尾空格后的权限字符串
permissions.contains(StringUtils.trim(permission));
}
这是个判断是否包含某个权限的私有方法。如果权限集合 permissions 是*:*:*
或者 permissions 中包含 permission 这个权限返回 true
否则返回 false
。
验证用户是否具备某权限
/**
* 验证用户是否具备某权限
*
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
public boolean hasPermi(String permission)
{ // 如果 permission 为空,直接返回 false
if (StringUtils.isEmpty(permission))
{
return false;
}
// 获取当前登录用户
LoginUser loginUser = SecurityUtils.getLoginUser();
// 如果当前登录用户是 null 或者当前登录用户拥有的权限 permissions 是空的返回 false
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
{
return false;
}
// 将传入的权限列表设置到权限上下文中
PermissionContextHolder.setContext(permission);
// 调用方法判断权限集合 permissions 中是否包含 权限 permission
return hasPermissions(loginUser.getPermissions(), permission);
}
这个方法就是判断当前登录用户是否拥有某个权限。
验证用户是否不具备某权限
/**
* 验证用户是否不具备某权限,与 hasPermi逻辑相反
*
* @param permission 权限字符串
* @return 用户是否不具备某权限
*/
public boolean lacksPermi(String permission)
{
return hasPermi(permission) != true;
}
lacksPermi
方法是验证当前登录用户是否不具备某权限,与hasPermi
方法逻辑正好相反
验证用户是否具有以下任意一个权限
/**
* 验证用户是否具有以下任意一个权限
*
* @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表
* @return 用户是否具有以下任意一个权限
*/
public boolean hasAnyPermi(String permissions)
{ // 如果 permission 为空,直接返回 false
if (StringUtils.isEmpty(permissions))
{
return false;
}
// 获取当前登录用户
LoginUser loginUser = SecurityUtils.getLoginUser();
// 如果当前登录用户是 null 或者当前登录用户拥有的权限 permissions 是空的返回 false
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
{
return false;
}
// 将传入的权限列表设置到权限上下文中
PermissionContextHolder.setContext(permissions);
// 获取当前登录用户拥有的权限集合
Set<String> authorities = loginUser.getPermissions();
// 根据权限分割符进行分隔然后进行 for 循环
for (String permission : permissions.split(Constants.PERMISSION_DELIMETER))
{
// 逐个判断分隔后的权限是否包含在登录用户拥有的权限集合中
if (permission != null && hasPermissions(authorities, permission))
{
return true;
}
}
return false;
}
这个方法的大体逻辑和上面的hasPermi
方法是一样的,只不过这个是有多个权限循环判断是否具有其中一个权限。
判断用户是否拥有某个角色
/**
* 判断用户是否拥有某个角色
*
* @param role 角色字符串
* @return 用户是否具备某角色
*/
public boolean hasRole(String role)
{ // role 为空直接返回 false
if (StringUtils.isEmpty(role))
{
return false;
}
// 获取当前登录用户
LoginUser loginUser = SecurityUtils.getLoginUser();
// 如果当前登录用户为null 或者 登录用户拥有的角色是空的,返回 false
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
{
return false;
}
// for 循环当前用户拥有的角色
for (SysRole sysRole : loginUser.getUser().getRoles())
{ // 获取角色的权限字符
String roleKey = sysRole.getRoleKey();
// 如果登录用户拥有 `admin` 的权限或者登录用户拥有的权限字符和传入的权限字符 role 是一致的,返回 true
if (Constants.SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role)))
{
return true;
}
}
return false;
}
在若依中每个角色都有一个唯一的权限字符。
这个方法是判断当前用户配置的角色拥有的权限字符和传入的权限字符做对比看是否拥有传入的权限。如果是超级管理员admin
默认拥有全部权限。
验证用户是否不具备某角色
/**
* 验证用户是否不具备某角色,与 isRole逻辑相反。
*
* @param role 角色名称
* @return 用户是否不具备某角色
*/
public boolean lacksRole(String role)
{
return hasRole(role) != true;
}
这个方法的逻辑和hasRole
方法正好相反,验证的是用户是否不具备某角色的
验证用户是否具有以下任意一个角色
/**
* 验证用户是否具有以下任意一个角色
*
* @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
* @return 用户是否具有以下任意一个角色
*/
public boolean hasAnyRoles(String roles)
{
// roles 为空,直接返回 false
if (StringUtils.isEmpty(roles))
{
return false;
}
// 获取当前登录用户
LoginUser loginUser = SecurityUtils.getLoginUser();
// 登录用户为空或者登录用户拥有的角色为空返回 false
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
{
return false;
}
// 根据分隔符对 roles 进行分隔然后 for 循环
for (String role : roles.split(Constants.ROLE_DELIMETER))
{
// 调用 `hasRole`方法验证登录用户是否拥有这个角色,如果拥有返回 true
if (hasRole(role))
{
return true;
}
}
return false;
}
这个方法是调用了上面的hasRole
方法实现的,基本逻辑大差不差。只是这个方法可以传入用分隔符连接的多个角色的字符串,然后它循环判断是否具有其中任意一个角色。