一、上节回顾
在上一节中,我们介绍了如何通过数据库查询用户的权限,并对方法级别的接口使用注解的方式进行权限控制,之后通过用户携带的tocken进行解析权限,判断是否可以访问。
具体步骤:
1.在查询用户信息的时候将用户权限查询出来,并给前端返回一个tocken。2.编写一个后端过滤:作用主要是通过自定义的jwt工具将tocken进行解析,将解析出来的权限信息告诉给springsecurity。
3.将自定义的过滤器加载到springsecurity中的过滤器链中。
4.在方法级别的接口上通过@PreAuthorize("hasAnyAuthority('qxgl')") //需要的权限进行权限控制。
5.访问验证
那么上述方案有一个问题,在真实项目中,接口是非常多的,并且通过注解的方式进行权限控制的话,那么当接口权限发生变化的时候,改动量是非常大的,所以我们需要动态的设置接口权限。
二、动态权限的实现思路
1.每一个页面或者是按钮都有一个访问接口,那么我们就需要在menu表中增加访问接口的字段。
2.编写一个类实现AuthorizationManager接口,在这个接口中,我们需要查询出当前访问接口所需要的权限,然后根据当前用户的权限进行比对,如果有则放行。
2.在springsecurity的配制文件中,添加access配置并传入自定义类
三、动态权限实现步骤
1..每一个页面或者是按钮都有一个访问接口,那么我们就需要在menu表中增加访问接口的字段。
CREATE TABLE `menu` (`id` int NOT NULL COMMENT 'id',`menu_name` varchar(255) DEFAULT NULL COMMENT '权限名称',`menu_tag` varchar(255) DEFAULT NULL COMMENT '权限标签',`parent_id` int DEFAULT NULL COMMENT '父id',`menu_type` int DEFAULT NULL COMMENT '权限类型(1:目录,2:菜单,3:按钮)',`is_deleted` int DEFAULT NULL COMMENT '是否删除',`path` varchar(255) DEFAULT NULL COMMENT '访问路径',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
2.编写一个类实现AuthorizationManager接口,在这个接口中,我们需要查询出当前访问接口所需要的权限,然后根据当前用户的权限进行比对,如果有则放行。
package com.ljy.myspringbootlogin.filter;/*** 这个类主要作用:实现动态权限* 1.实现AuthorizationManager* 2.重写其中的check()方法* 3.获取前端的请求路径(其中登录接口不需要认证)* 4.根据请求路径查询所需要的权限*//*** RequestAuthorizationContext 我们需要从这里取出请求接口路径*/import com.ljy.myspringbootlogin.model.MenuModel;
import com.ljy.myspringbootlogin.service.IMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.function.Supplier;
import java.util.stream.Collectors;@Component
public class SpringSecurityAuyhorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
@AutowiredIMenuService iMenuService;@Overridepublic AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {//获取前端的请求路径HttpServletRequest request = requestAuthorizationContext.getRequest();String requestURI = request.getRequestURI();StringBuffer requestURL = request.getRequestURL();System.out.println("uri: "+requestURI);System.out.println("url: "+requestURL);//登录接口不需要认证if("/sys/login".equals(requestURI)){return new AuthorizationDecision(true);}//根据前端的请求路径查询menuMenuModel menuByPath = iMenuService.getMenuByPath(requestURI);if(menuByPath==null){return new AuthorizationDecision(false);}//获取所需要的权限String menuTag = menuByPath.getMenuTag();System.out.println("路径权限:"+menuTag);if(menuTag == null || menuTag.trim().equals("")){return new AuthorizationDecision(true);}//和用户的权限集合进行判断Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();for (GrantedAuthority authority : authorities) {String userParam = authority.getAuthority();System.out.println("用户权限:"+userParam);if(userParam.equals(menuTag)){return new AuthorizationDecision(true);}}return new AuthorizationDecision(false);}
}
3.在springsecurity的配置文件中配置
http.authorizeHttpRequests().antMatchers("/sys/**").permitAll()
// .anyRequest().authenticated();.anyRequest().access(springSecurityAuyhorizationManager); //动态实现权限
4.测试