权限框架的搭建

一. 思路
二. 具体实现
     2.1 配置拦截器
     2.2 具体拦截器的处理方法
     2.3 注解的配置
     2.4 权限的配置
     2.5 注解的使用
     2.6 总结
三. 提升(白名单,默认全都要有权限)

一. 思路
          总体思路还是 利用 拦截器拦截每一个请求。
  1. 请求过来,拦截器拦截。
  2. 取得 该请求的方法,对应取得方法上(或者是类上)的权限注解。
  3. 再 通过 请求 传来的 用户Id 来得到用户被赋予的权限。
  4. 对比 方法上的权限注解 和 用户被赋予的权限。
  5. 匹配上 则让其通过,否则,不让其通过。 

二.具体实现
2.1 配置 拦截器。

          Spring Boot 配置拦截器可以继承 WebMvcAutoConfigurationAdaptor。如下代码: 

import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PrivilegeConfiguration extends WebMvcAutoConfigurationAdapter{
	
	@Bean
	public PrivilegeInterceptor createPrivilegeFilter(){
		return new PrivilegeInterceptor();
	}
	
	@Override
	public void addInterceptors(org.springframework.web.servlet.config.annotation.InterceptorRegistry registry) {
		registry.addInterceptor(createPrivilegeFilter());
	};
}

2.2 具体的拦截器的处理方法:

@Slf4j
public class PrivilegeInterceptor implements HandlerInterceptor{
	
	@Autowired
	private StaffService staffService;
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	
		log.info("PrivilegeInterceptor class ... preHandle function ... ");
		
		//获得类的权限注解 和方法的权限注解
		HandlerMethod handlerMethod = (HandlerMethod) handler;
		
		PrivilegeRequired privilegeRequiredClass = handlerMethod.getBeanType().getAnnotation(PrivilegeRequired.class);
		PrivilegeRequired privilegeRequiredMethod = handlerMethod.getMethodAnnotation(PrivilegeRequired.class);
		
		log.info("PrivilegeInterceptor class ... privilegeRequiredClass = {}.",privilegeRequiredClass);
		log.info("PrivilegeInterceptor class ... privilegeRequiredMethod = {}.",privilegeRequiredMethod);
		
		//如果没有,那么则允许通过
		if(privilegeRequiredClass == null && privilegeRequiredMethod == null) return true;
		
		
		//如果有,那么 先把权限收集,最后比较
		Set<Privilege> priv = new HashSet<>();
		if(privilegeRequiredClass != null){
			 priv.addAll(Arrays.asList(privilegeRequiredClass.value()));
		}
		if(privilegeRequiredMethod != null){
			 priv.addAll(Arrays.asList(privilegeRequiredMethod.value()));
		}
        Privilege[] privileges = priv.toArray(new Privilege[priv.size()]);
			
		//对用户进行权限比较
		String staffId = request.getParameter("staffId");
        if(staffId == null || staffId.isEmpty())  return false;
        
        Staff staff = staffService.findStaffById(staffId);
        if(staff == null) return false;
        
        Set<Role> granted = (Set<Role>) staff.getRoleList();
        log.info("PrivilegeInterceptor class ... granted = {}.",granted);
        
        for (Privilege privilege : privileges) {
        	for (Role role : granted) {
        		if (role.getRoleName().equals(privilege.getPrivilege())) {
        			
        			log.info("PrivilegeInterceptor class ... granted pass. -> role.getRoleName() = {}. privilege.getPrivilege() = {}.",
        					role.getRoleName(),privilege.getPrivilege());
        			
                    return true;
                }
			}
            
        }
		
        log.info("PrivilegeInterceptor class ... method not allowed.Beacuse of no authority.");
        
		return false;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		
	}

}

Ps:这里的 二重 for 循环 可以改为 JDK1.8 的 并行流,提高效率。


2.3 注解的配置

@Documented
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE, ElementType.METHOD})
public @interface PrivilegeRequired {
    /**
     * The name/code of the privileges required
     * 
     * @return 
     */
    public Privilege[] value();
}

2.4 权限的配置

@ToString
public enum Privilege {
	
	STAFF("STAFF"), //员工权限
	
	ADMIN("ADMIN");  //管理员权限
	
	private String privilege;
	
	private Privilege(String privilege){this.privilege = privilege;}
	
	public String getPrivilege(){
		return this.privilege;
	}
}

2.5 注解的使用:

在方法前(或者是类的前面)加入:

@PrivilegeRequired(Privilege.ADMIN)

2.6 总结:
          拦截器的配置 和 权限之间的对比都不是特别的困难。就是 注意 如何取得类前面的权限 和方法前面的权限。使用利用了  HandlerMethod,该类的对象可以被 handler强转,然后就可以取得目前要访问的方法,从而也有方法获得权限相关的信息,也可以获得类上面的信息。
               另外还有一个就是如何定义注解的问题。


三. 提升(白名单,默认全都要有权限)
          有些程序员(包括本人)经常会忘记在方法前面写权限限制,这是不好的习惯,也和程序员自身水平有关。上面的Demo 的做法是 不写权限的注解,那么就默认没有权限,所有人都可以访问,这样其实不是特别好,因为实际上有些是需要权限的,只是程序员忘了。
          所以另外一个解决办法可以是:默认所有的方法都不可以进入,需要权限才可以进入。如果实际上是真的不需要权限就可以进入,那么也要加一个 FreePrivilege 之类的注解。也就是说,没有权限也是权限的一种。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值