> 文章列表 > 4.功能权限

4.功能权限

4.功能权限

基于角色的权限控制,用户分配角色,角色分配菜单。

1. 权限注解

1.基于【权限标识】的权限控制

权限标识,对应 system_menu 表的 permission 字段,推荐格式为 {系统}:{模块}:{操作},例如说 system:admin:add 标识 system 服务的添加管理员。
4.功能权限

  • @PreAuthorize (opens new window)是 Spring Security 内置的前置权限注解,添加在接口方法上,声明需要的权限,实现访问权限的控制。
  • 当 @PreAuthorize 注解里的 Spring EL 表达式返回 false 时,表示没有权限。

ss是自动配置类中注入的一个名字为ss的bean,传入的是PermissionApi接口的一个实现类,返回的是SecurityFrameworkServiceImpl类型
4.功能权限
传入的实现类定义在system模块下
4.功能权限
返回的实体类在
4.功能权限

这样当访问一个接口时,会进到SecurityFrameworkServiceImpl类的hasPermission方法。传入的就是controller中的system:dept:update
4.功能权限
然后继续往下调用
4.功能权限
PermissionApi就是PermissionApiImpl类型
4.功能权限
然后会调用permissionService的hasAnyPermissions方法
4.功能权限
然后进入判断逻辑
4.功能权限

    @Overridepublic boolean hasAnyPermissions(Long userId, String... permissions) {// 如果为空,说明已经有权限,也就是controller传入的权限就是空,也就是可以不加注解if (ArrayUtil.isEmpty(permissions)) {return true;}// 获得当前登录的角色(从缓存)。如果为空,说明没有权限,传入当前用户id和开启的status 0//流程就是获取到当前用户的所有角色id 然后判断这些角色是否为关闭状态Set<Long> roleIds = getUserRoleIdsFromCache(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));if (CollUtil.isEmpty(roleIds)) {return false;}// 判断是否是超管。如果是,当然符合条件if (roleService.hasAnySuperAdmin(roleIds)) {return true;}// 遍历权限,判断是否有一个满足return Arrays.stream(permissions).anyMatch(permission -> {//根据permission获取菜单,获取不到说明没有权限List<MenuDO> menuList = menuService.getMenuListByPermissionFromCache(permission);// 采用严格模式,如果权限找不到对应的 Menu 的话,认为if (CollUtil.isEmpty(menuList)) {return false;}// 获得是否拥有该权限,任一一个//获取到菜单,去缓存中根据菜单id看是否能匹配当前角色//anyMatch用法 遍历menuList,//CollUtil.containsAny(roleIds, menuRoleCache.get(menu.getId()))有一个返回true的话,就返回truereturn menuList.stream().anyMatch(menu -> CollUtil.containsAny(roleIds,menuRoleCache.get(menu.getId())));});}

这样这个判断就完成了。

2.基于角色的权限控制

    @Overridepublic boolean hasAnyRoles(Long userId, String... roles) {// 如果为空,说明已经有权限if (ArrayUtil.isEmpty(roles)) {return true;}// 获得当前登录的角色。如果为空,说明没有权限Set<Long> roleIds = getUserRoleIdsFromCache(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));if (CollUtil.isEmpty(roleIds)) {return false;}// 判断是否是超管。如果是,当然符合条件if (roleService.hasAnySuperAdmin(roleIds)) {return true;}Set<String> userRoles = convertSet(roleService.getRoleListFromCache(roleIds),RoleDO::getCode);return CollUtil.containsAny(userRoles, Sets.newHashSet(roles));}

3.登陆判断

@PreAuthenticated 注解

  • @PreAuthenticated (opens new window)是项目自定义的认证注解,添加在接口方法上,声明登录的用户才允许访问。
  • 主要使用场景是,针对用户 App 的 /app-app/** 的 RESTful API 接口,默认是无需登录的,通过 @PreAuthenticated 声明它需要进行登录。

针对这个注解的aop
4.功能权限
如果加了这个注解而且没有登录,会抛出异常,然后会被GlobalExceptionHandler类的serviceExceptionHandler方法捕获。返回前端异常信息。

2.自定义权限配置

1.自定义 AuthorizeRequestsCustomizer 实现

例如yudao-module-infra 模块的 SecurityConfiguration ()类

@Configuration("infraSecurityConfiguration")
public class SecurityConfiguration {@Value("${spring.boot.admin.context-path:''}")private String adminSeverContextPath;@Bean("infraAuthorizeRequestsCustomizer")public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {return new AuthorizeRequestsCustomizer() {@Overridepublic void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) {// Swagger 接口文档registry.antMatchers("/swagger-ui.html").anonymous().antMatchers("/swagger-resources/**").anonymous().antMatchers("/webjars/**").anonymous().antMatchers("/*/api-docs").anonymous();// Spring Boot Actuator 的安全配置registry.antMatchers("/actuator").anonymous().antMatchers("/actuator/**").anonymous();// Druid 监控registry.antMatchers("/druid/**").anonymous();// Spring Boot Admin Server 的安全配置registry.antMatchers(adminSeverContextPath).anonymous().antMatchers(adminSeverContextPath + "/**").anonymous();}};}}
  • permitAll() 方法:所有用户可以任意访问,包括带上 Token 访问
  • anonymous() 方法:匿名用户可以任意访问,带上 Token 访问会报错

2.@PermitAll 注解

直接在接口方法加这个注解

3.配置文件配置

4.功能权限