SpringBoot集成Spring Security权限控制

2022-08-08 11:58:22

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

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

1. 表结构

CREATETABLE`sys_permission`(`id`int(11)NOTNULLAUTO_INCREMENT,`url`varchar(50)DEFAULTNULL,`role_id`int(11)DEFAULTNULL,`permission`varchar(20)DEFAULTNULL,PRIMARYKEY(`id`),KEY`fk_roleId`(`role_id`),CONSTRAINT`fk_roleId`FOREIGNKEY(`role_id`)REFERENCES`sys_role`(`id`)ONDELETECASCADEONUPDATECASCADE)ENGINE=InnoDBAUTO_INCREMENT=5DEFAULTCHARSET=utf8;

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

2. 三层结构

2.1 实体类(enity)

/**
 * 权限实体类
 */@Data@AllArgsConstructor@NoArgsConstructorpublicclassSysPermissionimplementsSerializable{staticfinallong serialVersionUID=1L;//idprivateint id;//具有权限的地址privateString url;//角色privateint roleId;//权限privateString permission;//权限集privateList permissions;publicListgetPermissions(){returnArrays.asList(this.permission.trim().split(","));}publicvoidsetPermissions(List permissions){this.permissions=permissions;}}

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

@Mapper@RepositorypublicinterfaceSysPermissionMapper{//根据用户查找出来权限@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

@ServicepublicclassSysPermissionService{@AutowiredprivateSysPermissionMapper sysPermission;/**
     * 获得角色的所有权限
     */publicList<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')")publicStringprintAdminR(){return"访问的/admin具有r权限";}@RequestMapping("/admin/c")@ResponseBody@PreAuthorize("hasPermission('/admin','c')")publicStringprintAdminC(){return"访问的/admin具有c权限";}

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

3. PermissionEvaluator

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

/**
 * 自定义权限处理
 */@ComponentpublicclassCustomPermissionEvaluatorimplementsPermissionEvaluator{@AutowiredprivateSysPermissionService permissionService;@AutowiredprivateSysRoleService roleService;//参数 1 代表用户的权限身份,参数 2 参数 3 分别和 @PreAuthorize("hasPermission('/admin','r')") 中的参数对应,即访问 url 和权限。@OverridepublicbooleanhasPermission(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);//遍历所有权限,即遍历permissionListfor(SysPermission permission:permissionList){//获取权限集List permissions=permission.getPermissions();// 如果访问的Url和权限用户符合的话,返回trueif(targetUrl.equals(permission.getUrl())&&  permissions.contains(targetPermission)){returntrue;}}}returnfalse;}@OverridepublicbooleanhasPermission(Authentication authentication,Serializable serializable,String s,Object o){returnfalse;}}

  其中方法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
     */@BeanpublicDefaultWebSecurityExpressionHandlerwebSecurityExpressionHandler(){DefaultWebSecurityExpressionHandler handler=newDefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(newCustomPermissionEvaluator());return handler;}

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

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

不然编译会报错

4. 程序运行

在这里插入图片描述

  • 作者:飞鸟~~~
  • 原文链接:https://blog.csdn.net/qq_39371480/article/details/119698780
    更新时间:2022-08-08 11:58:22