SpringBoot集成Spring Security(5)——权限控制

SpringBoot集成Spring Security(5)——权限控制

  这里的权限只是对角色赋予权限,也就是说同一个角色的用户,权限是一样的。

1. 表结构

CREATE TABLE `sys_permission` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `url` varchar(50) DEFAULT NULL,
  `role_id` int(11) DEFAULT NULL,
  `permission` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_roleId` (`role_id`),
  CONSTRAINT `fk_roleId` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

  添加两条数据,url+role_id+permission 唯一标识了一个角色访问某一 url 时的权限,其中权限暂定为 c、r、u、d,即增删改查。

2. 三层结构

2.1 实体类(enity)

/**
 * 权限实体类
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysPermission implements Serializable {
    static final long serialVersionUID = 1L;
    //id
    private int id;
    //具有权限的地址
    private String url;
    //角色
    private int roleId;
    //权限
    private String permission;
    //权限集
    private List permissions;

    public List getPermissions(){
        return Arrays.asList(this.permission.trim().split(","));
    }

    public void setPermissions(List permissions){
        this.permissions=permissions;
    }
}

  由于在数据库中直接设定有个角色对应了很多权限,我们需要单独地提取出这些权限放在一个集合中来获取,方便后面的使用。故多了一个 permissions 属性,该字段将 permission 按逗号分割为了 list
2.2 mapper
2.2.1 添加SysPermissionMapper接口

@Mapper
@Repository
public interface SysPermissionMapper {

    //根据用户查找出来权限
    @Select("select * from sys_permission where role_id=#{roleId}")
    List<SysPermission> listByRoleId(int roleId);
}

2.2.2 修改SysUserMapper
在这里插入图片描述
2.3 service
2.3.1 添加SysPermissionService类
  SysPermissionService 中有一个方法,根据 roleId 获取所有的 SysPermission

@Service
public class SysPermissionService {

    @Autowired
    private SysPermissionMapper sysPermission;

    /**
     * 获得角色的所有权限
     */
    public List<SysPermission> listByRoleId(int roleId){
        return sysPermission.listByRoleId(roleId);
    }
}

2.3.2 修改SysRoleService类
在这里插入图片描述
2.4 controller
  在LoginController中添加权限处理,但得把之前的认证处理注释掉,不然会报创建bean异常,因为有相同的RequestMapping

    //权限处理
    @RequestMapping("/admin")
    @ResponseBody
    @PreAuthorize("hasPermission('/admin','r')")
    public String printAdminR(){
        return "访问的/admin具有r权限";
    }

    @RequestMapping("/admin/c")
    @ResponseBody
    @PreAuthorize("hasPermission('/admin','c')")
    public String printAdminC(){
        return "访问的/admin具有c权限";
    }

  接着修改访问的接口,其中@PreAuthorize("hasPermission('/admin','r')")是关键,参数1(/admin)指明了访问该接口需要的url,参数2®指明了访问该接口需要的权限

3. PermissionEvaluator

  对 hasPermission() 方法的处理,就需要自定义 PermissionEvaluator,创建类 CustomPermissionEvaluator,实现 PermissionEvaluator 接口

/**
 * 自定义权限处理
 */
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private SysRoleService roleService;

    //参数 1 代表用户的权限身份,参数 2 参数 3 分别和 @PreAuthorize("hasPermission('/admin','r')") 中的参数对应,即访问 url 和权限。
    @Override
    public boolean hasPermission(Authentication authentication, Object targetUrl, Object targetPermission) {
        //获得loadUserByUsername()方法的结果
        User user= (User) authentication.getPrincipal();
        //获得loadUserByUsername()中注入的角色
        Collection<GrantedAuthority> authorities=user.getAuthorities();

        //遍历所有角色
        for(GrantedAuthority authority:authorities){
            String roleName=authority.getAuthority();
            int roleId=roleService.selectByRole(roleName).getId();
            //得到角色的所有权限
            List<SysPermission> permissionList=permissionService.listByRoleId(roleId);

            //遍历所有权限,即遍历permissionList
            for(SysPermission permission:permissionList){
                //获取权限集
                List permissions=permission.getPermissions();
                // 如果访问的Url和权限用户符合的话,返回true
                if(targetUrl.equals(permission.getUrl())
                        &&  permissions.contains(targetPermission)){
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable serializable, String s, Object o) {
        return false;
    }
}

  其中方法 hasPermission(Authentication authentication, Object targetUrl, Object targetPermission),第一个参数authentication(用户的权限身份),第二个参数Object targetUrl(访问的url,即/admin),第三个参数Object targetPermission(这个url需要的权限)
  思路如下:

  • 通过 Authentication 取出登录用户的所有 role
  • 遍历每一个 role,获取到每个role的所有 permission
  • 遍历每一个 permission,只要有一个 permission 的 url 和传入的url相同,且该 permission 中包含传入的权限,返回 true
  • 如果遍历都结束,还没有找到,返回false

  在WebSecurityConfig 中注册添加 CustomPermissionEvaluator

 /**
     * 自定义注入权限PermissionEvaluator
     */
    @Bean
    public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler(){
        DefaultWebSecurityExpressionHandler handler=new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(new CustomPermissionEvaluator());
        return handler;
    }

  在配置文件application.properties中添加:

spring.main.allow-bean-definition-overriding=true

不然编译会报错

4. 程序运行

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值