一、上节回顾
在上一节中,我们介绍了如何通过数据库查询用户的权限,并对方法级别的接口使用注解的方式进行权限控制,之后通过用户携带的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> {
@Autowired
IMenuService iMenuService;
@Override
public 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);
}
//根据前端的请求路径查询menu
MenuModel 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.测试