SpringBootSecurity学习(11)网页版登录之URL动态权限

动态权限

前面讨论用户登录认证的时候,根据用户名查询用户会将用户拥有的角色一起查询出来,自动实现判断当前登录用户拥有哪些角色。可以说用户与角色之间的动态配置和判断security做的非常不错。不过在配置方法级别的权限的时候,使用注解虽然是一种比较优雅的方式,但是要求在开发的时候就知道当前url对应哪些角色,无法实现动态的配置,而实际的项目中,每个链接允许哪些角色访问也不是一成不变的,因此下面我们来实现自己的路由判断。

创建表

前面的讨论中,我们创建了用户表,角色表和用户角色中间表,下面来创建菜单功能表,并把现在有的url链接添加进去:

file

然后创建角色菜单中间表,加入角色与url之间的对应关系:

file

创建基础类

首先去掉前面的方法级别权限的注解,然后创建菜单实体类:

file

创建查询方法,根据url查询次链接对应的所有角色名称:

file

对应的sql语句如下:

file

路由动态获取角色

首先增加一个处理类,在收到访问的时候,动态获取当前url的角色:

file

新建一个ObjectPostProcessor类,将这个处理类配置到其中:

file

最后将新建的ObjectPostProcessor类配置到权限配置方法中:

file

路由决策管理

用户与角色是多对多的关系,url与角色也是多对多的关系,这里的设定是,只要用户与url对应的角色中有相同的存在,就表示用户有访问的权限。首先看一下对应判断的处理类:

file

使用双重for循环进行判断,并进行结果投票。在注释中可以看到,使用不同的方式会产生不同的策略。下一步在security配置类中配置路由策略方法:

file

除了UrlRoleAuthHandler类,其它决策类使用的都是security存在的类,最后在权限配置中配置决策管理:

file

测试

这样动态权限url就配置好了,根据上面方法中的数据,可以登录查看是否具有对应的url权限,没有配置的是否不具备权限。

代码地址:https://gitee.com/blueses/spring-boot-security 11

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot Security提供了动态权限管理的支持,可以在运行时动态地添加、修改和删除用户权限,而无需重新启动应用程序。以下是实现动态权限的步骤: 1. 配置Spring SecuritySpring Security配置类中,需要指定权限管理器和访问决策管理器: ``` @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailsService userDetailsService; @Autowired private CustomPermissionEvaluator permissionEvaluator; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .accessDecisionManager(accessDecisionManager()) .and() .formLogin() .and() .httpBasic() .and() .csrf().disable(); } @Bean public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() { DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler(); handler.setPermissionEvaluator(permissionEvaluator); return handler; } @Bean public AccessDecisionManager accessDecisionManager() { List<AccessDecisionVoter<?>> decisionVoters = Arrays.asList( new WebExpressionVoter(), new RoleVoter(), new AuthenticatedVoter(), new CustomPermissionVoter(permissionEvaluator) ); return new AffirmativeBased(decisionVoters); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` 2. 实现自定义权限管理器和访问决策管理器 自定义权限管理器和访问决策管理器是实现动态权限管理的关键。权限管理器负责加载用户权限,访问决策管理器负责根据用户权限决策是否允许访问某个资源。 ``` @Component public class CustomPermissionEvaluator implements PermissionEvaluator { @Autowired private PermissionService permissionService; @Override public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) { if (authentication == null || targetDomainObject == null || !(permission instanceof String)) { return false; } CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal(); String targetType = targetDomainObject.getClass().getSimpleName().toUpperCase(); PermissionType permissionType = PermissionType.valueOf((String) permission); return permissionService.hasPermission(userDetails.getUserId(), targetType, permissionType); } @Override public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) { if (authentication == null || targetType == null || !(permission instanceof String)) { return false; } CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal(); PermissionType permissionType = PermissionType.valueOf((String) permission); return permissionService.hasPermission(userDetails.getUserId(), targetType.toUpperCase(), permissionType); } } @Component public class CustomPermissionVoter extends AbstractAccessDecisionVoter<Object> { private final PermissionEvaluator permissionEvaluator; public CustomPermissionVoter(PermissionEvaluator permissionEvaluator) { super("ROLE_USER"); this.permissionEvaluator = permissionEvaluator; } @Override public boolean supports(ConfigAttribute attribute) { return attribute.getAttribute() != null && attribute.getAttribute().startsWith("PERM_"); } @Override public boolean supports(Class<?> clazz) { return true; } @Override public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) { int result = ACCESS_ABSTAIN; CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal(); for (ConfigAttribute attribute : attributes) { if (this.supports(attribute)) { result = ACCESS_DENIED; String permission = attribute.getAttribute().substring(5); Object targetObject = object; if (object instanceof FilterInvocation) { FilterInvocation filterInvocation = (FilterInvocation) object; HttpServletRequest request = filterInvocation.getRequest(); targetObject = new CustomWebSecurityExpressionRoot(authentication, request); } if (permissionEvaluator.hasPermission(authentication, targetObject, permission)) { return ACCESS_GRANTED; } } } return result; } } ``` 3. 实现自定义用户权限加载器 自定义用户权限加载器负责从数据库或其他数据源中加载用户权限,可以在运行时动态地添加、修改和删除用户权限。 ``` @Service public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserService userService; @Autowired private PermissionService permissionService; @Override public CustomUserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userService.getUserByUsername(username); if (user == null) { throw new UsernameNotFoundException("User not found"); } List<Permission> permissions = permissionService.getPermissionsByUserId(user.getId()); Set<GrantedAuthority> authorities = new HashSet<>(); for (Permission permission : permissions) { authorities.add(new SimpleGrantedAuthority("PERM_" + permission.getPermissionType())); } return new CustomUserDetails(user.getId(), user.getUsername(), user.getPassword(), authorities); } } ``` 4. 实现自定义权限管理器 自定义权限管理器负责将用户权限加载到Spring Security的安全上下文中。 ``` @Component public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { private final Map<String, Collection<ConfigAttribute>> resourceMap = new ConcurrentHashMap<>(); @Autowired private PermissionService permissionService; @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { if (object instanceof FilterInvocation) { FilterInvocation filterInvocation = (FilterInvocation) object; HttpServletRequest request = filterInvocation.getRequest(); String url = request.getRequestURI(); String method = request.getMethod(); String key = url + ":" + method; if (resourceMap.containsKey(key)) { return resourceMap.get(key); } else { List<Permission> permissions = permissionService.getPermissionsByUrlAndMethod(url, method); Collection<ConfigAttribute> configAttributes = new HashSet<>(); for (Permission permission : permissions) { configAttributes.add(new SecurityConfig("PERM_" + permission.getPermissionType())); } resourceMap.put(key, configAttributes); return configAttributes; } } return null; } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } @Override public boolean supports(Class<?> clazz) { return FilterInvocation.class.isAssignableFrom(clazz); } } ``` 5. 实现自定义权限服务 自定义权限服务负责提供添加、修改和删除用户权限的接口。 ``` @Service public class PermissionService { @Autowired private PermissionRepository permissionRepository; public List<Permission> getPermissionsByUserId(Long userId) { return permissionRepository.findByUserId(userId); } public List<Permission> getPermissionsByUrlAndMethod(String url, String method) { return permissionRepository.findByUrlAndMethod(url, method); } public boolean hasPermission(Long userId, String targetType, PermissionType permissionType) { List<Permission> permissions = permissionRepository.findByUserIdAndTargetTypeAndPermissionType(userId, targetType, permissionType); return !permissions.isEmpty(); } public void addPermission(Permission permission) { permissionRepository.save(permission); } public void updatePermission(Permission permission) { permissionRepository.save(permission); } public void deletePermission(Long permissionId) { permissionRepository.deleteById(permissionId); } } ``` 6. 在运行时动态添加、修改和删除用户权限 在需要添加、修改和删除用户权限的地方,调用自定义权限服务的接口即可。 例如,可以实现一个RESTful API,用于添加、修改和删除用户权限: ``` @RestController @RequestMapping("/permissions") public class PermissionController { @Autowired private PermissionService permissionService; @PostMapping public void addPermission(@RequestBody Permission permission) { permissionService.addPermission(permission); } @PutMapping("/{id}") public void updatePermission(@PathVariable Long id, @RequestBody Permission permission) { permission.setId(id); permissionService.updatePermission(permission); } @DeleteMapping("/{id}") public void deletePermission(@PathVariable Long id) { permissionService.deletePermission(id); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值